From ea024155fb6333058525908f4fee3fa60dd1f70a Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 22 Aug 2016 15:20:22 -0700 Subject: [PATCH] Add lifecycle observers for future mixin structures. - Converted VisibilityLoggerMixin into a LifecyclerObservable so we don't have to call logger.onResume/onPause manually in most fragments. - Observable will be useful when we provide logics across all fragment/activity, eg log lifecycle event latencies. - Also added new tests for lifecycle component. Bug: 30681529 Test: RunSettingsRoboTests Change-Id: Ida39300aeb42f71b2e0bbfaebd0c51dc468cb5e8 --- .../android/settings/DeviceAdminSettings.java | 6 +- .../settings/UserDictionarySettings.java | 6 +- src/com/android/settings/ZonePicker.java | 7 +- .../settings/core/InstrumentedActivity.java | 19 +-- .../settings/core/InstrumentedFragment.java | 24 ++-- .../VisibilityLoggerMixin.java | 26 ++-- .../settings/core/lifecycle/Lifecycle.java | 86 +++++++++++++ .../core/lifecycle/LifecycleObserver.java | 22 ++++ .../core/lifecycle/ObservableActivity.java | 60 +++++++++ .../ObservablePreferenceFragment.java | 54 ++++++++ .../core/lifecycle/events/OnDestroy.java | 20 +++ .../core/lifecycle/events/OnPause.java | 20 +++ .../core/lifecycle/events/OnResume.java | 20 +++ .../core/lifecycle/events/OnStart.java | 21 ++++ .../core/lifecycle/events/OnStop.java | 21 ++++ .../android/settings/utils/ThreadUtils.java | 42 +++++++ .../VisibilityLoggerMixinTest.java | 6 +- .../core/lifecycle/LifecycleTest.java | 115 ++++++++++++++++++ .../settings/utils/ThreadUtilsTest.java | 61 ++++++++++ 19 files changed, 583 insertions(+), 53 deletions(-) create mode 100644 src/com/android/settings/core/lifecycle/Lifecycle.java create mode 100644 src/com/android/settings/core/lifecycle/LifecycleObserver.java create mode 100644 src/com/android/settings/core/lifecycle/ObservableActivity.java create mode 100644 src/com/android/settings/core/lifecycle/ObservablePreferenceFragment.java create mode 100644 src/com/android/settings/core/lifecycle/events/OnDestroy.java create mode 100644 src/com/android/settings/core/lifecycle/events/OnPause.java create mode 100644 src/com/android/settings/core/lifecycle/events/OnResume.java create mode 100644 src/com/android/settings/core/lifecycle/events/OnStart.java create mode 100644 src/com/android/settings/core/lifecycle/events/OnStop.java create mode 100644 src/com/android/settings/utils/ThreadUtils.java create mode 100644 tests/robotests/src/com/android/settings/core/lifecycle/LifecycleTest.java create mode 100644 tests/robotests/src/com/android/settings/utils/ThreadUtilsTest.java diff --git a/src/com/android/settings/DeviceAdminSettings.java b/src/com/android/settings/DeviceAdminSettings.java index aef4138c79c..f729678e947 100644 --- a/src/com/android/settings/DeviceAdminSettings.java +++ b/src/com/android/settings/DeviceAdminSettings.java @@ -64,7 +64,7 @@ public class DeviceAdminSettings extends ListFragment implements Instrumentable static final String TAG = "DeviceAdminSettings"; private final VisibilityLoggerMixin mVisibilityLoggerMixin = - new VisibilityLoggerMixin(this); + new VisibilityLoggerMixin(getMetricsCategory()); private DevicePolicyManager mDPM; private UserManager mUm; @@ -135,7 +135,7 @@ public class DeviceAdminSettings extends ListFragment implements Instrumentable public void onResume() { super.onResume(); final Activity activity = getActivity(); - mVisibilityLoggerMixin.onResume(activity); + mVisibilityLoggerMixin.onResume(); IntentFilter filter = new IntentFilter(); filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); activity.registerReceiverAsUser( @@ -158,7 +158,7 @@ public class DeviceAdminSettings extends ListFragment implements Instrumentable public void onPause() { final Activity activity = getActivity(); activity.unregisterReceiver(mBroadcastReceiver); - mVisibilityLoggerMixin.onPause(activity); + mVisibilityLoggerMixin.onPause(); super.onPause(); } diff --git a/src/com/android/settings/UserDictionarySettings.java b/src/com/android/settings/UserDictionarySettings.java index 7d6b5cbfc40..6e4d40ecc85 100644 --- a/src/com/android/settings/UserDictionarySettings.java +++ b/src/com/android/settings/UserDictionarySettings.java @@ -70,7 +70,7 @@ public class UserDictionarySettings extends ListFragment implements Instrumentab private static final int OPTIONS_MENU_ADD = Menu.FIRST; private final VisibilityLoggerMixin mVisibilityLoggerMixin = - new VisibilityLoggerMixin(this); + new VisibilityLoggerMixin(getMetricsCategory()); private Cursor mCursor; protected String mLocale; @@ -128,7 +128,7 @@ public class UserDictionarySettings extends ListFragment implements Instrumentab @Override public void onResume() { super.onResume(); - mVisibilityLoggerMixin.onResume(getActivity()); + mVisibilityLoggerMixin.onResume(); } private Cursor createCursor(final String locale) { @@ -192,7 +192,7 @@ public class UserDictionarySettings extends ListFragment implements Instrumentab @Override public void onPause() { super.onPause(); - mVisibilityLoggerMixin.onPause(getActivity()); + mVisibilityLoggerMixin.onPause(); } /** diff --git a/src/com/android/settings/ZonePicker.java b/src/com/android/settings/ZonePicker.java index b91463fbff8..0b52bdca709 100644 --- a/src/com/android/settings/ZonePicker.java +++ b/src/com/android/settings/ZonePicker.java @@ -58,7 +58,8 @@ public class ZonePicker extends ListFragment implements Instrumentable { private static final int MENU_TIMEZONE = Menu.FIRST+1; private static final int MENU_ALPHABETICAL = Menu.FIRST; - private final VisibilityLoggerMixin mVisibilityLoggerMixin = new VisibilityLoggerMixin(this); + private final VisibilityLoggerMixin mVisibilityLoggerMixin = + new VisibilityLoggerMixin(getMetricsCategory()); private boolean mSortedByTimezone; @@ -185,7 +186,7 @@ public class ZonePicker extends ListFragment implements Instrumentable { @Override public void onResume() { super.onResume(); - mVisibilityLoggerMixin.onResume(getActivity()); + mVisibilityLoggerMixin.onResume(); } @Override @@ -242,7 +243,7 @@ public class ZonePicker extends ListFragment implements Instrumentable { @Override public void onPause() { super.onPause(); - mVisibilityLoggerMixin.onPause(getActivity()); + mVisibilityLoggerMixin.onPause(); } private static class MyComparator implements Comparator> { diff --git a/src/com/android/settings/core/InstrumentedActivity.java b/src/com/android/settings/core/InstrumentedActivity.java index 02808be338d..891af5d0059 100644 --- a/src/com/android/settings/core/InstrumentedActivity.java +++ b/src/com/android/settings/core/InstrumentedActivity.java @@ -16,27 +16,18 @@ package com.android.settings.core; -import android.app.Activity; - import com.android.settings.core.instrumentation.Instrumentable; import com.android.settings.core.instrumentation.VisibilityLoggerMixin; +import com.android.settings.core.lifecycle.ObservableActivity; /** * Instrumented activity that logs visibility state. */ -public abstract class InstrumentedActivity extends Activity implements Instrumentable { +public abstract class InstrumentedActivity extends ObservableActivity implements Instrumentable { - private final VisibilityLoggerMixin mVisibilityLoggerMixin = new VisibilityLoggerMixin(this); - - @Override - public void onResume() { - super.onResume(); - mVisibilityLoggerMixin.onResume(this); + public InstrumentedActivity() { + // Mixin that logs visibility change for activity. + getLifecycle().addObserver(new VisibilityLoggerMixin(getMetricsCategory())); } - @Override - public void onPause() { - super.onPause(); - mVisibilityLoggerMixin.onPause(this); - } } diff --git a/src/com/android/settings/core/InstrumentedFragment.java b/src/com/android/settings/core/InstrumentedFragment.java index 1efbdcf792e..7fa9fc52c4f 100644 --- a/src/com/android/settings/core/InstrumentedFragment.java +++ b/src/com/android/settings/core/InstrumentedFragment.java @@ -17,31 +17,23 @@ package com.android.settings.core; import android.os.Bundle; -import android.support.v14.preference.PreferenceFragment; -import com.android.settings.core.instrumentation.VisibilityLoggerMixin; import com.android.settings.core.instrumentation.Instrumentable; +import com.android.settings.core.instrumentation.VisibilityLoggerMixin; +import com.android.settings.core.lifecycle.ObservablePreferenceFragment; /** * Instrumented fragment that logs visibility state. */ -public abstract class InstrumentedFragment extends PreferenceFragment implements Instrumentable { +public abstract class InstrumentedFragment extends ObservablePreferenceFragment + implements Instrumentable { - private final VisibilityLoggerMixin mVisibilityLoggerMixin = new VisibilityLoggerMixin(this); + public InstrumentedFragment() { + // Mixin that logs visibility change for activity. + getLifecycle().addObserver(new VisibilityLoggerMixin(getMetricsCategory())); + } @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { } - - @Override - public void onResume() { - super.onResume(); - mVisibilityLoggerMixin.onResume(getActivity()); - } - - @Override - public void onPause() { - super.onPause(); - mVisibilityLoggerMixin.onPause(getActivity()); - } } diff --git a/src/com/android/settings/core/instrumentation/VisibilityLoggerMixin.java b/src/com/android/settings/core/instrumentation/VisibilityLoggerMixin.java index 29a804b6a7c..28fdf34f583 100644 --- a/src/com/android/settings/core/instrumentation/VisibilityLoggerMixin.java +++ b/src/com/android/settings/core/instrumentation/VisibilityLoggerMixin.java @@ -16,30 +16,34 @@ package com.android.settings.core.instrumentation; -import android.content.Context; +import com.android.settings.core.lifecycle.LifecycleObserver; +import com.android.settings.core.lifecycle.events.OnPause; +import com.android.settings.core.lifecycle.events.OnResume; /** * Logs visibility change of a fragment. */ -public class VisibilityLoggerMixin { +public class VisibilityLoggerMixin implements LifecycleObserver, OnResume, OnPause { - private final Instrumentable mInstrumentable; + private final int mMetricsCategory; private final LogWriter mLogWriter; - public VisibilityLoggerMixin(Instrumentable instrumentable) { - this(instrumentable, MetricsFactory.get().getLogger()); + public VisibilityLoggerMixin(int metricsCategory) { + this(metricsCategory, MetricsFactory.get().getLogger()); } - public VisibilityLoggerMixin(Instrumentable instrumentable, LogWriter logWriter) { - mInstrumentable = instrumentable; + public VisibilityLoggerMixin(int metricsCategory, LogWriter logWriter) { + mMetricsCategory = metricsCategory; mLogWriter = logWriter; } - public void onResume(Context context) { - mLogWriter.visible(context, mInstrumentable.getMetricsCategory()); + @Override + public void onResume() { + mLogWriter.visible(null /* context */, mMetricsCategory); } - public void onPause(Context context) { - mLogWriter.hidden(context, mInstrumentable.getMetricsCategory()); + @Override + public void onPause() { + mLogWriter.hidden(null /* context */, mMetricsCategory); } } diff --git a/src/com/android/settings/core/lifecycle/Lifecycle.java b/src/com/android/settings/core/lifecycle/Lifecycle.java new file mode 100644 index 00000000000..8c60ef4b7cb --- /dev/null +++ b/src/com/android/settings/core/lifecycle/Lifecycle.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.core.lifecycle; + +import android.annotation.UiThread; + +import com.android.settings.core.lifecycle.events.OnDestroy; +import com.android.settings.core.lifecycle.events.OnPause; +import com.android.settings.core.lifecycle.events.OnResume; +import com.android.settings.core.lifecycle.events.OnStart; +import com.android.settings.core.lifecycle.events.OnStop; +import com.android.settings.utils.ThreadUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * Dispatcher for lifecycle events. + */ +public class Lifecycle { + + protected final List mObservers = new ArrayList<>(); + + /** + * Registers a new observer of lifecycle events. + */ + @UiThread + public T addObserver(T observer) { + ThreadUtils.ensureMainThread(); + mObservers.add(observer); + return observer; + } + + public void onStart() { + for (LifecycleObserver observer : mObservers) { + if (observer instanceof OnStart) { + ((OnStart) observer).onStart(); + } + } + } + + public void onResume() { + for (LifecycleObserver observer : mObservers) { + if (observer instanceof OnResume) { + ((OnResume) observer).onResume(); + } + } + } + + public void onPause() { + for (LifecycleObserver observer : mObservers) { + if (observer instanceof OnPause) { + ((OnPause) observer).onPause(); + } + } + } + + public void onStop() { + for (LifecycleObserver observer : mObservers) { + if (observer instanceof OnStop) { + ((OnStop) observer).onStop(); + } + } + } + + public void onDestroy() { + for (LifecycleObserver observer : mObservers) { + if (observer instanceof OnDestroy) { + ((OnDestroy) observer).onDestroy(); + } + } + } +} diff --git a/src/com/android/settings/core/lifecycle/LifecycleObserver.java b/src/com/android/settings/core/lifecycle/LifecycleObserver.java new file mode 100644 index 00000000000..1f88e853a1d --- /dev/null +++ b/src/com/android/settings/core/lifecycle/LifecycleObserver.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.core.lifecycle; + +/** + * Observer of lifecycle events. + */ +public interface LifecycleObserver { +} diff --git a/src/com/android/settings/core/lifecycle/ObservableActivity.java b/src/com/android/settings/core/lifecycle/ObservableActivity.java new file mode 100644 index 00000000000..179e3caac2f --- /dev/null +++ b/src/com/android/settings/core/lifecycle/ObservableActivity.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.core.lifecycle; + +import android.app.Activity; + +/** + * {@link Activity} that has hooks to observe activity lifecycle events. + */ +public class ObservableActivity extends Activity { + + private final Lifecycle mLifecycle = new Lifecycle(); + + protected Lifecycle getLifecycle() { + return mLifecycle; + } + + @Override + protected void onStart() { + mLifecycle.onStart(); + super.onStart(); + } + + @Override + protected void onResume() { + mLifecycle.onResume(); + super.onResume(); + } + + @Override + protected void onPause() { + mLifecycle.onPause(); + super.onPause(); + } + + @Override + protected void onStop() { + mLifecycle.onStop(); + super.onStop(); + } + + @Override + protected void onDestroy() { + mLifecycle.onDestroy(); + super.onDestroy(); + } +} diff --git a/src/com/android/settings/core/lifecycle/ObservablePreferenceFragment.java b/src/com/android/settings/core/lifecycle/ObservablePreferenceFragment.java new file mode 100644 index 00000000000..f994a8ca31e --- /dev/null +++ b/src/com/android/settings/core/lifecycle/ObservablePreferenceFragment.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.core.lifecycle; + + +import android.annotation.CallSuper; +import android.support.v14.preference.PreferenceFragment; + +/** + * {@link PreferenceFragment} that has hooks to observe fragment lifecycle events. + */ +public abstract class ObservablePreferenceFragment extends PreferenceFragment { + + private final Lifecycle mLifecycle = new Lifecycle(); + + protected Lifecycle getLifecycle() { + return mLifecycle; + } + + @CallSuper + @Override + public void onStart() { + mLifecycle.onStart(); + super.onStart(); + } + + @CallSuper + @Override + public void onResume() { + mLifecycle.onResume(); + super.onResume(); + } + + @CallSuper + @Override + public void onPause() { + mLifecycle.onPause(); + super.onPause(); + } + +} diff --git a/src/com/android/settings/core/lifecycle/events/OnDestroy.java b/src/com/android/settings/core/lifecycle/events/OnDestroy.java new file mode 100644 index 00000000000..5499de82782 --- /dev/null +++ b/src/com/android/settings/core/lifecycle/events/OnDestroy.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.core.lifecycle.events; + +public interface OnDestroy { + void onDestroy(); +} diff --git a/src/com/android/settings/core/lifecycle/events/OnPause.java b/src/com/android/settings/core/lifecycle/events/OnPause.java new file mode 100644 index 00000000000..155af00ce33 --- /dev/null +++ b/src/com/android/settings/core/lifecycle/events/OnPause.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.core.lifecycle.events; + +public interface OnPause { + void onPause(); +} diff --git a/src/com/android/settings/core/lifecycle/events/OnResume.java b/src/com/android/settings/core/lifecycle/events/OnResume.java new file mode 100644 index 00000000000..30ce42b15df --- /dev/null +++ b/src/com/android/settings/core/lifecycle/events/OnResume.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.core.lifecycle.events; + +public interface OnResume { + void onResume(); +} diff --git a/src/com/android/settings/core/lifecycle/events/OnStart.java b/src/com/android/settings/core/lifecycle/events/OnStart.java new file mode 100644 index 00000000000..3b4e6cc6928 --- /dev/null +++ b/src/com/android/settings/core/lifecycle/events/OnStart.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.core.lifecycle.events; + +public interface OnStart { + + void onStart(); +} diff --git a/src/com/android/settings/core/lifecycle/events/OnStop.java b/src/com/android/settings/core/lifecycle/events/OnStop.java new file mode 100644 index 00000000000..8c19b87b173 --- /dev/null +++ b/src/com/android/settings/core/lifecycle/events/OnStop.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.core.lifecycle.events; + +public interface OnStop { + + void onStop(); +} diff --git a/src/com/android/settings/utils/ThreadUtils.java b/src/com/android/settings/utils/ThreadUtils.java new file mode 100644 index 00000000000..f71a2a9c269 --- /dev/null +++ b/src/com/android/settings/utils/ThreadUtils.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.utils; + +import android.os.Looper; + +public class ThreadUtils { + private static volatile Thread sMainThread; + + /** + * Returns true if the current thread is the UI thread. + */ + public static boolean isMainThread() { + if (sMainThread == null) { + sMainThread = Looper.getMainLooper().getThread(); + } + return Thread.currentThread() == sMainThread; + } + + /** + * Checks that the current thread is the UI thread. Otherwise throws an exception. + */ + public static void ensureMainThread() { + if (!isMainThread()) { + throw new RuntimeException("Must be called on the UI thread"); + } + } + +} diff --git a/tests/robotests/src/com/android/settings/core/instrumentation/VisibilityLoggerMixinTest.java b/tests/robotests/src/com/android/settings/core/instrumentation/VisibilityLoggerMixinTest.java index 3940029356c..6d2abb3f30f 100644 --- a/tests/robotests/src/com/android/settings/core/instrumentation/VisibilityLoggerMixinTest.java +++ b/tests/robotests/src/com/android/settings/core/instrumentation/VisibilityLoggerMixinTest.java @@ -44,19 +44,19 @@ public class VisibilityLoggerMixinTest { @Before public void init() { MockitoAnnotations.initMocks(this); - mMixin = new VisibilityLoggerMixin(new TestInstrumentable(), mLogger); + mMixin = new VisibilityLoggerMixin(TestInstrumentable.TEST_METRIC, mLogger); } @Test public void shouldLogVisibleOnResume() { - mMixin.onResume(null); + mMixin.onResume(); verify(mLogger, times(1)) .visible(any(Context.class), eq(TestInstrumentable.TEST_METRIC)); } @Test public void shouldLogHideOnPause() { - mMixin.onPause(null); + mMixin.onPause(); verify(mLogger, times(1)) .hidden(any(Context.class), eq(TestInstrumentable.TEST_METRIC)); } diff --git a/tests/robotests/src/com/android/settings/core/lifecycle/LifecycleTest.java b/tests/robotests/src/com/android/settings/core/lifecycle/LifecycleTest.java new file mode 100644 index 00000000000..042d5ca6c41 --- /dev/null +++ b/tests/robotests/src/com/android/settings/core/lifecycle/LifecycleTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.core.lifecycle; + +import android.app.Fragment; +import android.app.FragmentManager; +import android.app.FragmentTransaction; +import android.os.Bundle; + +import com.android.settings.TestConfig; +import com.android.settings.core.lifecycle.events.OnDestroy; +import com.android.settings.core.lifecycle.events.OnPause; +import com.android.settings.core.lifecycle.events.OnResume; +import com.android.settings.core.lifecycle.events.OnStart; +import com.android.settings.core.lifecycle.events.OnStop; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.util.ActivityController; + +import static org.junit.Assert.assertTrue; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class LifecycleTest { + + public static class TestActivity extends ObservableActivity { + + final Fragment mFragment; + final TestObserver mActObserver; + + public TestActivity() { + mFragment = new Fragment(); + mActObserver = new TestObserver(); + getLifecycle().addObserver(mActObserver); + } + + @Override + public void onCreate(Bundle b) { + super.onCreate(b); + FragmentManager fragmentManager = getFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + fragmentTransaction.add(mFragment, "tag"); + fragmentTransaction.commit(); + } + } + + public static class TestObserver implements LifecycleObserver, OnStart, OnResume, + OnPause, OnStop, OnDestroy { + + boolean mOnStartObserved; + boolean mOnResumeObserved; + boolean mOnPauseObserved; + boolean mOnStopObserved; + boolean mOnDestroyObserved; + + @Override + public void onStart() { + mOnStartObserved = true; + } + + @Override + public void onPause() { + mOnPauseObserved = true; + } + + @Override + public void onResume() { + mOnResumeObserved = true; + } + + @Override + public void onStop() { + mOnStopObserved = true; + } + + @Override + public void onDestroy() { + mOnDestroyObserved = true; + } + } + + @Test + public void runThroughLifecycles_shouldObserveEverything() { + ActivityController ac = Robolectric.buildActivity(TestActivity.class); + TestActivity activity = ac.get(); + + ac.create().start(); + assertTrue(activity.mActObserver.mOnStartObserved); + ac.resume(); + assertTrue(activity.mActObserver.mOnResumeObserved); + ac.pause(); + assertTrue(activity.mActObserver.mOnPauseObserved); + ac.stop(); + assertTrue(activity.mActObserver.mOnStopObserved); + ac.destroy(); + assertTrue(activity.mActObserver.mOnDestroyObserved); + } +} diff --git a/tests/robotests/src/com/android/settings/utils/ThreadUtilsTest.java b/tests/robotests/src/com/android/settings/utils/ThreadUtilsTest.java new file mode 100644 index 00000000000..25119e0897d --- /dev/null +++ b/tests/robotests/src/com/android/settings/utils/ThreadUtilsTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.utils; + + +import com.android.settings.TestConfig; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class ThreadUtilsTest { + + @Test + public void testMainThread() throws InterruptedException { + assertTrue(ThreadUtils.isMainThread()); + Thread background = new Thread(new Runnable() { + public void run() { + assertFalse(ThreadUtils.isMainThread()); + } + }); + background.start(); + background.join(); + } + + @Test + public void testEnsureMainThread() throws InterruptedException { + ThreadUtils.ensureMainThread(); + Thread background = new Thread(new Runnable() { + public void run() { + try { + ThreadUtils.ensureMainThread(); + fail("Should not pass ensureMainThread in a background thread"); + } catch (RuntimeException e) { + } + } + }); + background.start(); + background.join(); + } +}