summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/BatteryMeterView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/LifecycleFragment.java87
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/SysuiLifecycle.java69
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java88
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java129
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java87
8 files changed, 497 insertions, 8 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 04c427f87125..38dadd4b961d 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -19,6 +19,8 @@ import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
import static android.app.StatusBarManager.DISABLE_NONE;
import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
+import static com.android.systemui.util.SysuiLifecycle.viewAttachLifecycle;
+
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.animation.ArgbEvaluator;
@@ -166,6 +168,7 @@ public class BatteryMeterView extends LinearLayout implements
setClipChildren(false);
setClipToPadding(false);
+ Dependency.get(ConfigurationController.class).observe(viewAttachLifecycle(this), this);
}
public void setForceShowPercent(boolean show) {
@@ -289,7 +292,6 @@ public class BatteryMeterView extends LinearLayout implements
Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser);
updateShowPercent();
subscribeForTunerUpdates();
- Dependency.get(ConfigurationController.class).addCallback(this);
mUserTracker.startTracking();
}
@@ -300,7 +302,6 @@ public class BatteryMeterView extends LinearLayout implements
mBatteryController.removeCallback(this);
getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
unsubscribeFromTunerUpdates();
- Dependency.get(ConfigurationController.class).removeCallback(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index d2bfd123f113..ae0a1452905d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -32,7 +32,6 @@ import android.annotation.IdRes;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
-import android.app.Fragment;
import android.app.IActivityTaskManager;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
@@ -90,6 +89,7 @@ import com.android.systemui.statusbar.phone.ContextualButton.ContextButtonListen
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyButtonView;
+import com.android.systemui.util.LifecycleFragment;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -101,7 +101,7 @@ import java.util.function.Consumer;
* Fragment containing the NavigationBarFragment. Contains logic for what happens
* on clicks and view states of the nav bar.
*/
-public class NavigationBarFragment extends Fragment implements Callbacks {
+public class NavigationBarFragment extends LifecycleFragment implements Callbacks {
public static final String TAG = "NavigationBar";
private static final boolean DEBUG = false;
@@ -199,7 +199,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCommandQueue = SysUiServiceProvider.getComponent(getContext(), CommandQueue.class);
- mCommandQueue.addCallback(this);
+ mCommandQueue.observe(getLifecycle(), this);
mStatusBar = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
mRecents = SysUiServiceProvider.getComponent(getContext(), Recents.class);
mDivider = SysUiServiceProvider.getComponent(getContext(), Divider.class);
@@ -225,7 +225,6 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
@Override
public void onDestroy() {
super.onDestroy();
- mCommandQueue.removeCallback(this);
Dependency.get(AccessibilityManagerWrapper.class).removeCallback(
mAccessibilityListener);
mContentResolver.unregisterContentObserver(mMagnificationObserver);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java
index 9042ca6d15ca..626eef5867f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java
@@ -1,8 +1,9 @@
/*
* 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
+ * 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
*
@@ -14,7 +15,35 @@
package com.android.systemui.statusbar.policy;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.Lifecycle.Event;
+import androidx.lifecycle.LifecycleEventObserver;
+import androidx.lifecycle.LifecycleOwner;
+
public interface CallbackController<T> {
void addCallback(T listener);
void removeCallback(T listener);
+
+ /**
+ * Wrapper to {@link #addCallback(Object)} when a lifecycle is in the resumed state
+ * and {@link #removeCallback(Object)} when not resumed automatically.
+ */
+ default T observe(LifecycleOwner owner, T listener) {
+ return observe(owner.getLifecycle(), listener);
+ }
+
+ /**
+ * Wrapper to {@link #addCallback(Object)} when a lifecycle is in the resumed state
+ * and {@link #removeCallback(Object)} when not resumed automatically.
+ */
+ default T observe(Lifecycle lifecycle, T listener) {
+ lifecycle.addObserver((LifecycleEventObserver) (lifecycleOwner, event) -> {
+ if (event == Event.ON_RESUME) {
+ addCallback(listener);
+ } else if (event == Event.ON_PAUSE) {
+ removeCallback(listener);
+ }
+ });
+ return listener;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/LifecycleFragment.java b/packages/SystemUI/src/com/android/systemui/util/LifecycleFragment.java
new file mode 100644
index 000000000000..c7f385dcf88c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/LifecycleFragment.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 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.systemui.util;
+
+import static androidx.lifecycle.Lifecycle.Event.ON_CREATE;
+import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY;
+import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+import static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
+import android.annotation.CallSuper;
+import android.app.Fragment;
+import android.os.Bundle;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+
+/**
+ * Version of {@link #Fragment} that is a {@link LifecycleOwner}.
+ */
+public class LifecycleFragment extends Fragment implements LifecycleOwner {
+
+ private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
+
+ public Lifecycle getLifecycle() {
+ return mLifecycle;
+ }
+
+ @CallSuper
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ mLifecycle.handleLifecycleEvent(ON_CREATE);
+ super.onCreate(savedInstanceState);
+ }
+
+ @CallSuper
+ @Override
+ public void onStart() {
+ mLifecycle.handleLifecycleEvent(ON_START);
+ super.onStart();
+ }
+
+ @CallSuper
+ @Override
+ public void onResume() {
+ mLifecycle.handleLifecycleEvent(ON_RESUME);
+ super.onResume();
+ }
+
+ @CallSuper
+ @Override
+ public void onPause() {
+ mLifecycle.handleLifecycleEvent(ON_PAUSE);
+ super.onPause();
+ }
+
+ @CallSuper
+ @Override
+ public void onStop() {
+ mLifecycle.handleLifecycleEvent(ON_STOP);
+ super.onStop();
+ }
+
+ @CallSuper
+ @Override
+ public void onDestroy() {
+ mLifecycle.handleLifecycleEvent(ON_DESTROY);
+ super.onDestroy();
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/SysuiLifecycle.java b/packages/SystemUI/src/com/android/systemui/util/SysuiLifecycle.java
new file mode 100644
index 000000000000..711a0dfe1931
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/SysuiLifecycle.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 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.systemui.util;
+
+import static androidx.lifecycle.Lifecycle.State.DESTROYED;
+import static androidx.lifecycle.Lifecycle.State.RESUMED;
+
+import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+
+/**
+ * Tools for generating lifecycle from sysui objects.
+ */
+public class SysuiLifecycle {
+
+ private SysuiLifecycle() {
+ }
+
+ /**
+ * Get a lifecycle that will be put into the resumed state when the view is attached
+ * and goes to the destroyed state when the view is detached.
+ */
+ public static LifecycleOwner viewAttachLifecycle(View v) {
+ return new ViewLifecycle(v);
+ }
+
+ private static class ViewLifecycle implements LifecycleOwner, OnAttachStateChangeListener {
+ private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
+
+ ViewLifecycle(View v) {
+ v.addOnAttachStateChangeListener(this);
+ }
+
+ @NonNull
+ @Override
+ public Lifecycle getLifecycle() {
+ return mLifecycle;
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ mLifecycle.markState(RESUMED);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ mLifecycle.markState(DESTROYED);
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
new file mode 100644
index 000000000000..93c97ec14a42
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 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.systemui.statusbar.policy;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.Lifecycle.Event;
+import androidx.lifecycle.LifecycleEventObserver;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+@RunWithLooper
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class CallbackControllerTest extends SysuiTestCase {
+
+ @Test
+ public void testAddCallback() {
+ Lifecycle lifecycle = mock(Lifecycle.class);
+ LifecycleOwner owner = () -> lifecycle;
+ Object callback = new Object();
+ Controller controller = mock(Controller.class);
+
+ // observe and get the lifecycle observer that gets registered.
+ ArgumentCaptor<LifecycleEventObserver> observer =
+ ArgumentCaptor.forClass(LifecycleEventObserver.class);
+ controller.observe(owner, callback);
+ verify(lifecycle).addObserver(observer.capture());
+
+ // move to resume state and make sure the callback gets registered.
+ observer.getValue().onStateChanged(owner, Event.ON_RESUME);
+ verify(controller).addCallback(eq(callback));
+ }
+
+ @Test
+ public void testRemoveCallback() {
+ Lifecycle lifecycle = mock(Lifecycle.class);
+ LifecycleOwner owner = () -> lifecycle;
+ Object callback = new Object();
+ Controller controller = mock(Controller.class);
+
+ // observe and get the lifecycle observer that gets registered.
+ ArgumentCaptor<LifecycleEventObserver> observer =
+ ArgumentCaptor.forClass(LifecycleEventObserver.class);
+ controller.observe(owner, callback);
+ verify(lifecycle).addObserver(observer.capture());
+
+ // move to pause state and make sure the callback gets unregistered.
+ observer.getValue().onStateChanged(owner, Event.ON_PAUSE);
+ verify(controller).removeCallback(eq(callback));
+ }
+
+ private static class Controller implements CallbackController<Object> {
+ @Override
+ public void addCallback(Object listener) {
+ }
+
+ @Override
+ public void removeCallback(Object listener) {
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java
new file mode 100644
index 000000000000..d4e38d8ea2f3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018 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.systemui.util;
+
+import static androidx.lifecycle.Lifecycle.Event.ON_CREATE;
+import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY;
+import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+import static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import androidx.lifecycle.LifecycleEventObserver;
+
+import com.android.systemui.SysuiBaseFragmentTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWithLooper
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class LifecycleFragmentTest extends SysuiBaseFragmentTest {
+
+ public LifecycleFragmentTest() {
+ super(LifecycleFragment.class);
+ }
+
+ @Test
+ public void testCreateLifecycle() {
+ LifecycleFragment fragment = (LifecycleFragment) mFragment;
+ LifecycleEventObserver observer = mock(LifecycleEventObserver.class);
+ fragment.getLifecycle().addObserver(observer);
+
+ mFragments.dispatchCreate();
+ TestableLooper.get(this).processAllMessages();
+
+ verify(observer).onStateChanged(eq(fragment), eq(ON_CREATE));
+ }
+
+ @Test
+ public void testResumeLifecycle() {
+ LifecycleFragment fragment = (LifecycleFragment) mFragment;
+ LifecycleEventObserver observer = mock(LifecycleEventObserver.class);
+ fragment.getLifecycle().addObserver(observer);
+
+ mFragments.dispatchResume();
+ TestableLooper.get(this).processAllMessages();
+
+ verify(observer).onStateChanged(eq(fragment), eq(ON_RESUME));
+ }
+
+ @Test
+ public void testStartLifecycle() {
+ LifecycleFragment fragment = (LifecycleFragment) mFragment;
+ LifecycleEventObserver observer = mock(LifecycleEventObserver.class);
+ fragment.getLifecycle().addObserver(observer);
+
+ mFragments.dispatchStart();
+ TestableLooper.get(this).processAllMessages();
+
+ verify(observer).onStateChanged(eq(fragment), eq(ON_START));
+ }
+
+ @Test
+ public void testStopLifecycle() {
+ LifecycleFragment fragment = (LifecycleFragment) mFragment;
+ LifecycleEventObserver observer = mock(LifecycleEventObserver.class);
+ fragment.getLifecycle().addObserver(observer);
+
+ mFragments.dispatchStart();
+ TestableLooper.get(this).processAllMessages();
+ mFragments.dispatchStop();
+ TestableLooper.get(this).processAllMessages();
+
+ verify(observer).onStateChanged(eq(fragment), eq(ON_STOP));
+ }
+
+ @Test
+ public void testPauseLifecycle() {
+ LifecycleFragment fragment = (LifecycleFragment) mFragment;
+ LifecycleEventObserver observer = mock(LifecycleEventObserver.class);
+ fragment.getLifecycle().addObserver(observer);
+
+ mFragments.dispatchResume();
+ TestableLooper.get(this).processAllMessages();
+ mFragments.dispatchPause();
+ TestableLooper.get(this).processAllMessages();
+
+ verify(observer).onStateChanged(eq(fragment), eq(ON_PAUSE));
+ }
+
+ @Test
+ public void testDestroyLifecycle() {
+ LifecycleFragment fragment = (LifecycleFragment) mFragment;
+ LifecycleEventObserver observer = mock(LifecycleEventObserver.class);
+ fragment.getLifecycle().addObserver(observer);
+
+ mFragments.dispatchCreate();
+ TestableLooper.get(this).processAllMessages();
+ mFragments.dispatchDestroy();
+ TestableLooper.get(this).processAllMessages();
+ mFragments = null;
+
+ verify(observer).onStateChanged(eq(fragment), eq(ON_DESTROY));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java
new file mode 100644
index 000000000000..d63bbe6326f3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 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.systemui.util;
+
+import static androidx.lifecycle.Lifecycle.Event.ON_CREATE;
+import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY;
+import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+import static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
+import static com.android.systemui.util.SysuiLifecycle.viewAttachLifecycle;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.testing.ViewUtils;
+import android.view.View;
+
+import androidx.lifecycle.LifecycleEventObserver;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWithLooper
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class SysuiLifecycleTest extends SysuiTestCase {
+
+ @Test
+ public void testAttach() {
+ View v = new View(mContext);
+ LifecycleEventObserver observer = mock(LifecycleEventObserver.class);
+ LifecycleOwner lifecycle = viewAttachLifecycle(v);
+ lifecycle.getLifecycle().addObserver(observer);
+
+ ViewUtils.attachView(v);
+ TestableLooper.get(this).processAllMessages();
+
+ verify(observer).onStateChanged(eq(lifecycle), eq(ON_CREATE));
+ verify(observer).onStateChanged(eq(lifecycle), eq(ON_START));
+ verify(observer).onStateChanged(eq(lifecycle), eq(ON_RESUME));
+
+ ViewUtils.detachView(v);
+ TestableLooper.get(this).processAllMessages();
+ }
+
+ @Test
+ public void testDetach() {
+ View v = new View(mContext);
+ LifecycleEventObserver observer = mock(LifecycleEventObserver.class);
+ LifecycleOwner lifecycle = viewAttachLifecycle(v);
+ lifecycle.getLifecycle().addObserver(observer);
+
+ ViewUtils.attachView(v);
+ TestableLooper.get(this).processAllMessages();
+
+ ViewUtils.detachView(v);
+ TestableLooper.get(this).processAllMessages();
+
+ verify(observer).onStateChanged(eq(lifecycle), eq(ON_PAUSE));
+ verify(observer).onStateChanged(eq(lifecycle), eq(ON_STOP));
+ verify(observer).onStateChanged(eq(lifecycle), eq(ON_DESTROY));
+ }
+}