OSDN Git Service

Add lifecycle observers for future mixin structures.
authorFan Zhang <zhfan@google.com>
Mon, 22 Aug 2016 22:20:22 +0000 (15:20 -0700)
committerFan Zhang <zhfan@google.com>
Tue, 23 Aug 2016 21:02:39 +0000 (14:02 -0700)
- 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

19 files changed:
src/com/android/settings/DeviceAdminSettings.java
src/com/android/settings/UserDictionarySettings.java
src/com/android/settings/ZonePicker.java
src/com/android/settings/core/InstrumentedActivity.java
src/com/android/settings/core/InstrumentedFragment.java
src/com/android/settings/core/instrumentation/VisibilityLoggerMixin.java
src/com/android/settings/core/lifecycle/Lifecycle.java [new file with mode: 0644]
src/com/android/settings/core/lifecycle/LifecycleObserver.java [new file with mode: 0644]
src/com/android/settings/core/lifecycle/ObservableActivity.java [new file with mode: 0644]
src/com/android/settings/core/lifecycle/ObservablePreferenceFragment.java [new file with mode: 0644]
src/com/android/settings/core/lifecycle/events/OnDestroy.java [new file with mode: 0644]
src/com/android/settings/core/lifecycle/events/OnPause.java [new file with mode: 0644]
src/com/android/settings/core/lifecycle/events/OnResume.java [new file with mode: 0644]
src/com/android/settings/core/lifecycle/events/OnStart.java [new file with mode: 0644]
src/com/android/settings/core/lifecycle/events/OnStop.java [new file with mode: 0644]
src/com/android/settings/utils/ThreadUtils.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/core/instrumentation/VisibilityLoggerMixinTest.java
tests/robotests/src/com/android/settings/core/lifecycle/LifecycleTest.java [new file with mode: 0644]
tests/robotests/src/com/android/settings/utils/ThreadUtilsTest.java [new file with mode: 0644]

index aef4138..f729678 100644 (file)
@@ -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();
     }
 
index 7d6b5cb..6e4d40e 100644 (file)
@@ -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();
     }
 
     /**
index b91463f..0b52bdc 100644 (file)
@@ -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<Map<?, ?>> {
index 02808be..891af5d 100644 (file)
 
 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 {
-
-    private final VisibilityLoggerMixin mVisibilityLoggerMixin = new VisibilityLoggerMixin(this);
+public abstract class InstrumentedActivity extends ObservableActivity implements Instrumentable {
 
-    @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);
-    }
 }
index 1efbdcf..7fa9fc5 100644 (file)
 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 {
-
-    private final VisibilityLoggerMixin mVisibilityLoggerMixin = new VisibilityLoggerMixin(this);
+public abstract class InstrumentedFragment extends ObservablePreferenceFragment
+        implements Instrumentable {
 
-    @Override
-    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+    public InstrumentedFragment() {
+        // Mixin that logs visibility change for activity.
+        getLifecycle().addObserver(new VisibilityLoggerMixin(getMetricsCategory()));
     }
 
     @Override
-    public void onResume() {
-        super.onResume();
-        mVisibilityLoggerMixin.onResume(getActivity());
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        mVisibilityLoggerMixin.onPause(getActivity());
+    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
     }
 }
index 29a804b..28fdf34 100644 (file)
 
 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 (file)
index 0000000..8c60ef4
--- /dev/null
@@ -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<LifecycleObserver> mObservers = new ArrayList<>();
+
+    /**
+     * Registers a new observer of lifecycle events.
+     */
+    @UiThread
+    public <T extends LifecycleObserver> 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 (file)
index 0000000..1f88e85
--- /dev/null
@@ -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 (file)
index 0000000..179e3ca
--- /dev/null
@@ -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 (file)
index 0000000..f994a8c
--- /dev/null
@@ -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 (file)
index 0000000..5499de8
--- /dev/null
@@ -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 (file)
index 0000000..155af00
--- /dev/null
@@ -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 (file)
index 0000000..30ce42b
--- /dev/null
@@ -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 (file)
index 0000000..3b4e6cc
--- /dev/null
@@ -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 (file)
index 0000000..8c19b87
--- /dev/null
@@ -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 (file)
index 0000000..f71a2a9
--- /dev/null
@@ -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");
+        }
+    }
+
+}
index 3940029..6d2abb3 100644 (file)
@@ -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 (file)
index 0000000..042d5ca
--- /dev/null
@@ -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<TestActivity> 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 (file)
index 0000000..25119e0
--- /dev/null
@@ -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();
+    }
+}