Cleanup and refactoring of test utilities
- Make leak checking faster by converting to fakes
- Requires making clean interfaces for all CallbackControllers
- Integrate leak checking into the TestableContext
Test: runtest systemui
Change-Id: Ic57a06360d01a0323ef26735a543e9d1805459e2
diff --git a/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java
index f87336c..447edac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java
@@ -26,6 +26,8 @@
import android.view.View;
import android.widget.FrameLayout;
+import com.android.systemui.utils.leaks.LeakCheckedTest;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -139,7 +141,7 @@
private class HostCallbacks extends FragmentHostCallback<FragmentTestCase> {
public HostCallbacks() {
- super(getTrackedContext(), FragmentTestCase.this.mHandler, 0);
+ super(mContext, FragmentTestCase.this.mHandler, 0);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/LeakCheckedTest.java b/packages/SystemUI/tests/src/com/android/systemui/LeakCheckedTest.java
deleted file mode 100644
index d64669d..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/LeakCheckedTest.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * 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.systemui;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentCallbacks;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import com.android.systemui.statusbar.phone.ManagedProfileController;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.DataSaverController;
-import com.android.systemui.statusbar.policy.FlashlightController;
-import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.SecurityController;
-import com.android.systemui.statusbar.policy.CallbackController;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.ZenModeController;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Base class for tests to check if receivers are left registered, services bound, or other
- * listeners listening.
- */
-public class LeakCheckedTest extends SysuiTestCase {
- private static final String TAG = "LeakCheckedTest";
-
- private final Map<String, Tracker> mTrackers = new HashMap<>();
- private final Map<Class, Object> mLeakCheckers = new ArrayMap<>();
- private TrackingContext mTrackedContext;
-
- @Rule
- public TestWatcher successWatcher = new TestWatcher() {
- @Override
- protected void succeeded(Description description) {
- verify();
- }
- };
-
- @Before
- public void setup() {
- mTrackedContext = new TrackingContext(mContext);
- addSupportedLeakCheckers();
- }
-
- public <T> T getLeakChecker(Class<T> cls) {
- T obj = (T) mLeakCheckers.get(cls);
- if (obj == null) {
- Assert.fail(cls.getName() + " is not supported by LeakCheckedTest yet");
- }
- return obj;
- }
-
- public Context getTrackedContext() {
- return mTrackedContext;
- }
-
- private Tracker getTracker(String tag) {
- Tracker t = mTrackers.get(tag);
- if (t == null) {
- t = new Tracker();
- mTrackers.put(tag, t);
- }
- return t;
- }
-
- public void verify() {
- mTrackers.values().forEach(Tracker::verify);
- }
-
- public static class Tracker {
- private Map<Object, LeakInfo> mObjects = new ArrayMap<>();
-
- LeakInfo getLeakInfo(Object object) {
- LeakInfo leakInfo = mObjects.get(object);
- if (leakInfo == null) {
- leakInfo = new LeakInfo();
- mObjects.put(object, leakInfo);
- }
- return leakInfo;
- }
-
- private void verify() {
- mObjects.values().forEach(LeakInfo::verify);
- }
- }
-
- public static class LeakInfo {
- private List<Throwable> mThrowables = new ArrayList<>();
-
- private LeakInfo() {
- }
-
- private void addAllocation(Throwable t) {
- // TODO: Drop off the first element in the stack trace here to have a cleaner stack.
- mThrowables.add(t);
- }
-
- private void clearAllocations() {
- mThrowables.clear();
- }
-
- public void verify() {
- if (mThrowables.size() == 0) return;
- Log.e(TAG, "Listener or binding not properly released");
- for (Throwable t : mThrowables) {
- Log.e(TAG, "Allocation found", t);
- }
- StringWriter writer = new StringWriter();
- mThrowables.get(0).printStackTrace(new PrintWriter(writer));
- Assert.fail("Listener or binding not properly released\n"
- + writer.toString());
- }
- }
-
- private void addSupportedLeakCheckers() {
- addListening("bluetooth", BluetoothController.class);
- addListening("location", LocationController.class);
- addListening("rotation", RotationLockController.class);
- addListening("zen", ZenModeController.class);
- addListening("cast", CastController.class);
- addListening("hotspot", HotspotController.class);
- addListening("flashlight", FlashlightController.class);
- addListening("user", UserInfoController.class);
- addListening("keyguard", KeyguardMonitor.class);
- addListening("battery", BatteryController.class);
- addListening("security", SecurityController.class);
- addListening("profile", ManagedProfileController.class);
- addListening("alarm", NextAlarmController.class);
- NetworkController network = addListening("network", NetworkController.class);
- doAnswer(new Answer<Void>() {
- @Override
- public Void answer(InvocationOnMock invocation) throws Throwable {
- getTracker("emergency").getLeakInfo(invocation.getArguments()[0])
- .addAllocation(new Throwable());
- return null;
- }
- }).when(network).addEmergencyListener(any());
- doAnswer(new Answer<Void>() {
- @Override
- public Void answer(InvocationOnMock invocation) throws Throwable {
- getTracker("emergency").getLeakInfo(invocation.getArguments()[0]).clearAllocations();
- return null;
- }
- }).when(network).removeEmergencyListener(any());
- DataSaverController datasaver = addListening("datasaver", DataSaverController.class);
- when(network.getDataSaverController()).thenReturn(datasaver);
- }
-
- private <T extends CallbackController> T addListening(final String tag, Class<T> cls) {
- T mock = mock(cls);
- doAnswer(new Answer<Void>() {
- @Override
- public Void answer(InvocationOnMock invocation) throws Throwable {
- getTracker(tag).getLeakInfo(invocation.getArguments()[0])
- .addAllocation(new Throwable());
- return null;
- }
- }).when(mock).addCallback(any());
- doAnswer(new Answer<Void>() {
- @Override
- public Void answer(InvocationOnMock invocation) throws Throwable {
- getTracker(tag).getLeakInfo(invocation.getArguments()[0]).clearAllocations();
- return null;
- }
- }).when(mock).removeCallback(any());
- mLeakCheckers.put(cls, mock);
- return mock;
- }
-
- class TrackingContext extends ContextWrapper {
- public TrackingContext(Context base) {
- super(base);
- }
-
- @Override
- public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
- getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable());
- return super.registerReceiver(receiver, filter);
- }
-
- @Override
- public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
- String broadcastPermission, Handler scheduler) {
- getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable());
- return super.registerReceiver(receiver, filter, broadcastPermission, scheduler);
- }
-
- @Override
- public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
- IntentFilter filter, String broadcastPermission, Handler scheduler) {
- getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable());
- return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
- scheduler);
- }
-
- @Override
- public void unregisterReceiver(BroadcastReceiver receiver) {
- getTracker("receiver").getLeakInfo(receiver).clearAllocations();
- super.unregisterReceiver(receiver);
- }
-
- @Override
- public boolean bindService(Intent service, ServiceConnection conn, int flags) {
- getTracker("service").getLeakInfo(conn).addAllocation(new Throwable());
- return super.bindService(service, conn, flags);
- }
-
- @Override
- public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
- Handler handler, UserHandle user) {
- getTracker("service").getLeakInfo(conn).addAllocation(new Throwable());
- return super.bindServiceAsUser(service, conn, flags, handler, user);
- }
-
- @Override
- public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
- UserHandle user) {
- getTracker("service").getLeakInfo(conn).addAllocation(new Throwable());
- return super.bindServiceAsUser(service, conn, flags, user);
- }
-
- @Override
- public void unbindService(ServiceConnection conn) {
- getTracker("service").getLeakInfo(conn).clearAllocations();
- super.unbindService(conn);
- }
-
- @Override
- public void registerComponentCallbacks(ComponentCallbacks callback) {
- getTracker("component").getLeakInfo(callback).addAllocation(new Throwable());
- super.registerComponentCallbacks(callback);
- }
-
- @Override
- public void unregisterComponentCallbacks(ComponentCallbacks callback) {
- getTracker("component").getLeakInfo(callback).clearAllocations();
- super.unregisterComponentCallbacks(callback);
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 5dac8e5..008580a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -22,6 +22,7 @@
import android.os.MessageQueue;
import com.android.systemui.utils.TestableContext;
+import com.android.systemui.utils.leaks.Tracker;
import org.junit.After;
import org.junit.Before;
@@ -29,14 +30,14 @@
/**
* Base class that does System UI specific setup.
*/
-public class SysuiTestCase {
+public abstract class SysuiTestCase {
private Handler mHandler;
protected TestableContext mContext;
@Before
public void SysuiSetup() throws Exception {
- mContext = new TestableContext(InstrumentationRegistry.getTargetContext());
+ mContext = new TestableContext(InstrumentationRegistry.getTargetContext(), this);
}
@After
@@ -71,6 +72,11 @@
}
}
+ // Used for leak tracking, returns null to indicate no leak tracking by default.
+ public Tracker getTracker(String tag) {
+ return null;
+ }
+
public static final class EmptyRunnable implements Runnable {
public void run() {
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 6ceaead..1973b54 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -38,6 +38,7 @@
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.tuner.TunerService;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -59,7 +60,7 @@
KeyguardMonitor keyguardMonitor = getLeakChecker(KeyguardMonitor.class);
when(userSwitcher.getKeyguardMonitor()).thenReturn(keyguardMonitor);
when(userSwitcher.getUsers()).thenReturn(new ArrayList<>());
- QSTileHost host = new QSTileHost(getTrackedContext(),
+ QSTileHost host = new QSTileHost(mContext,
mock(PhoneStatusBar.class),
getLeakChecker(BluetoothController.class),
getLeakChecker(LocationController.class),
@@ -86,5 +87,7 @@
waitForIdleSync(h);
host.destroy();
+ // Ensure the tuner cleans up its persistent listeners.
+ TunerService.get(mContext).destroy();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
index 5179823..bf73416 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
@@ -14,18 +14,31 @@
package com.android.systemui.utils;
+import android.content.BroadcastReceiver;
+import android.content.ComponentCallbacks;
import android.content.ContentProviderClient;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.UserHandle;
import android.provider.Settings;
+import com.android.systemui.utils.leaks.Tracker;
+import com.android.systemui.SysuiTestCase;
+
public class TestableContext extends ContextWrapper {
private final FakeContentResolver mFakeContentResolver;
private final FakeSettingsProvider mSettingsProvider;
- public TestableContext(Context base) {
+ private Tracker mReceiver;
+ private Tracker mService;
+ private Tracker mComponent;
+
+ public TestableContext(Context base, SysuiTestCase test) {
super(base);
mFakeContentResolver = new FakeContentResolver(base);
ContentProviderClient settings = base.getContentResolver()
@@ -33,6 +46,9 @@
mSettingsProvider = FakeSettingsProvider.getFakeSettingsProvider(settings,
mFakeContentResolver);
mFakeContentResolver.addProvider(Settings.AUTHORITY, mSettingsProvider);
+ mReceiver = test.getTracker("receiver");
+ mService = test.getTracker("service");
+ mComponent = test.getTracker("component");
}
public FakeSettingsProvider getSettingsProvider() {
@@ -49,4 +65,69 @@
// Return this so its always a TestableContext.
return this;
}
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ if (mReceiver != null) mReceiver.getLeakInfo(receiver).addAllocation(new Throwable());
+ return super.registerReceiver(receiver, filter);
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+ String broadcastPermission, Handler scheduler) {
+ if (mReceiver != null) mReceiver.getLeakInfo(receiver).addAllocation(new Throwable());
+ return super.registerReceiver(receiver, filter, broadcastPermission, scheduler);
+ }
+
+ @Override
+ public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+ IntentFilter filter, String broadcastPermission, Handler scheduler) {
+ if (mReceiver != null) mReceiver.getLeakInfo(receiver).addAllocation(new Throwable());
+ return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
+ scheduler);
+ }
+
+ @Override
+ public void unregisterReceiver(BroadcastReceiver receiver) {
+ if (mReceiver != null) mReceiver.getLeakInfo(receiver).clearAllocations();
+ super.unregisterReceiver(receiver);
+ }
+
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn, int flags) {
+ if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
+ return super.bindService(service, conn, flags);
+ }
+
+ @Override
+ public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+ Handler handler, UserHandle user) {
+ if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
+ return super.bindServiceAsUser(service, conn, flags, handler, user);
+ }
+
+ @Override
+ public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+ UserHandle user) {
+ if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
+ return super.bindServiceAsUser(service, conn, flags, user);
+ }
+
+ @Override
+ public void unbindService(ServiceConnection conn) {
+ if (mService != null) mService.getLeakInfo(conn).clearAllocations();
+ super.unbindService(conn);
+ }
+
+ @Override
+ public void registerComponentCallbacks(ComponentCallbacks callback) {
+ if (mComponent != null) mComponent.getLeakInfo(callback).addAllocation(new Throwable());
+ super.registerComponentCallbacks(callback);
+ }
+
+ @Override
+ public void unregisterComponentCallbacks(ComponentCallbacks callback) {
+ if (mComponent != null) mComponent.getLeakInfo(callback).clearAllocations();
+ super.unregisterComponentCallbacks(callback);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/BaseLeakChecker.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/BaseLeakChecker.java
new file mode 100644
index 0000000..0238bf7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/BaseLeakChecker.java
@@ -0,0 +1,40 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import com.android.systemui.statusbar.policy.CallbackController;
+
+public class BaseLeakChecker<T> implements CallbackController<T> {
+
+ private final Tracker mTracker;
+
+ public BaseLeakChecker(LeakCheckedTest test, String tag) {
+ mTracker = test.getTracker(tag);
+ }
+
+ protected final Tracker getTracker() {
+ return mTracker;
+ }
+
+ @Override
+ public void addCallback(T listener) {
+ mTracker.getLeakInfo(listener).addAllocation(new Throwable());
+ }
+
+ @Override
+ public void removeCallback(T listener) {
+ mTracker.getLeakInfo(listener).clearAllocations();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java
new file mode 100644
index 0000000..fa07d33
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java
@@ -0,0 +1,50 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import android.os.Bundle;
+
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+public class FakeBatteryController extends BaseLeakChecker<BatteryStateChangeCallback>
+ implements BatteryController {
+ public FakeBatteryController(LeakCheckedTest test) {
+ super(test, "battery");
+ }
+
+ @Override
+ public void dispatchDemoCommand(String command, Bundle args) {
+
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+
+ }
+
+ @Override
+ public void setPowerSaveMode(boolean powerSave) {
+
+ }
+
+ @Override
+ public boolean isPowerSave() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
new file mode 100644
index 0000000..6074a01
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
@@ -0,0 +1,84 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.BluetoothController.Callback;
+
+import java.util.Collection;
+
+public class FakeBluetoothController extends BaseLeakChecker<Callback> implements
+ BluetoothController {
+
+ public FakeBluetoothController(LeakCheckedTest test) {
+ super(test, "bluetooth");
+ }
+
+ @Override
+ public boolean isBluetoothSupported() {
+ return false;
+ }
+
+ @Override
+ public boolean isBluetoothEnabled() {
+ return false;
+ }
+
+ @Override
+ public int getBluetoothState() {
+ return 0;
+ }
+
+ @Override
+ public boolean isBluetoothConnected() {
+ return false;
+ }
+
+ @Override
+ public boolean isBluetoothConnecting() {
+ return false;
+ }
+
+ @Override
+ public String getLastDeviceName() {
+ return null;
+ }
+
+ @Override
+ public void setBluetoothEnabled(boolean enabled) {
+
+ }
+
+ @Override
+ public Collection<CachedBluetoothDevice> getDevices() {
+ return null;
+ }
+
+ @Override
+ public void connect(CachedBluetoothDevice device) {
+
+ }
+
+ @Override
+ public void disconnect(CachedBluetoothDevice device) {
+
+ }
+
+ @Override
+ public boolean canConfigBluetooth() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeCastController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeCastController.java
new file mode 100644
index 0000000..08211f8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeCastController.java
@@ -0,0 +1,51 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.CastController.Callback;
+
+import java.util.Set;
+
+public class FakeCastController extends BaseLeakChecker<Callback> implements CastController {
+ public FakeCastController(LeakCheckedTest test) {
+ super(test, "cast");
+ }
+
+ @Override
+ public void setDiscovering(boolean request) {
+
+ }
+
+ @Override
+ public void setCurrentUserId(int currentUserId) {
+
+ }
+
+ @Override
+ public Set<CastDevice> getCastDevices() {
+ return null;
+ }
+
+ @Override
+ public void startCasting(CastDevice device) {
+
+ }
+
+ @Override
+ public void stopCasting(CastDevice device) {
+
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeDataSaverController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeDataSaverController.java
new file mode 100644
index 0000000..857a785
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeDataSaverController.java
@@ -0,0 +1,35 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import com.android.systemui.statusbar.policy.DataSaverController;
+import com.android.systemui.statusbar.policy.DataSaverController.Listener;
+
+public class FakeDataSaverController extends BaseLeakChecker<Listener> implements DataSaverController {
+
+ public FakeDataSaverController(LeakCheckedTest test) {
+ super(test, "datasaver");
+ }
+
+ @Override
+ public boolean isDataSaverEnabled() {
+ return false;
+ }
+
+ @Override
+ public void setDataSaverEnabled(boolean enabled) {
+
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeFlashlightController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeFlashlightController.java
new file mode 100644
index 0000000..630abd7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeFlashlightController.java
@@ -0,0 +1,45 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.FlashlightController.FlashlightListener;
+
+public class FakeFlashlightController extends BaseLeakChecker<FlashlightListener>
+ implements FlashlightController {
+ public FakeFlashlightController(LeakCheckedTest test) {
+ super(test, "flashlight");
+ }
+
+ @Override
+ public boolean hasFlashlight() {
+ return false;
+ }
+
+ @Override
+ public void setFlashlight(boolean newState) {
+
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return false;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
new file mode 100644
index 0000000..781960d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
@@ -0,0 +1,40 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.HotspotController.Callback;
+
+public class FakeHotspotController extends BaseLeakChecker<Callback> implements HotspotController {
+
+ public FakeHotspotController(LeakCheckedTest test) {
+ super(test, "hotspot");
+ }
+
+ @Override
+ public boolean isHotspotEnabled() {
+ return false;
+ }
+
+ @Override
+ public void setHotspotEnabled(boolean enabled) {
+
+ }
+
+ @Override
+ public boolean isHotspotSupported() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java
new file mode 100644
index 0000000..39bbf2d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java
@@ -0,0 +1,51 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+
+public class FakeKeyguardMonitor implements KeyguardMonitor {
+
+ private final BaseLeakChecker<Callback> mCallbackController;
+
+ public FakeKeyguardMonitor(LeakCheckedTest test) {
+ mCallbackController = new BaseLeakChecker<Callback>(test, "keyguard");
+ }
+
+ @Override
+ public void addCallback(Callback callback) {
+ mCallbackController.addCallback(callback);
+ }
+
+ @Override
+ public void removeCallback(Callback callback) {
+ mCallbackController.removeCallback(callback);
+ }
+
+ @Override
+ public boolean isSecure() {
+ return false;
+ }
+
+ @Override
+ public boolean isShowing() {
+ return false;
+ }
+
+ @Override
+ public boolean canSkipBouncer() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeLocationController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeLocationController.java
new file mode 100644
index 0000000..eab436c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeLocationController.java
@@ -0,0 +1,35 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback;
+
+public class FakeLocationController extends BaseLeakChecker<LocationSettingsChangeCallback>
+ implements LocationController {
+ public FakeLocationController(LeakCheckedTest test) {
+ super(test, "location");
+ }
+
+ @Override
+ public boolean isLocationEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean setLocationEnabled(boolean enabled) {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeManagedProfileController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeManagedProfileController.java
new file mode 100644
index 0000000..0ec0d77
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeManagedProfileController.java
@@ -0,0 +1,40 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import com.android.systemui.statusbar.phone.ManagedProfileController;
+import com.android.systemui.statusbar.phone.ManagedProfileController.Callback;
+
+public class FakeManagedProfileController extends BaseLeakChecker<Callback> implements
+ ManagedProfileController {
+ public FakeManagedProfileController(LeakCheckedTest test) {
+ super(test, "profile");
+ }
+
+ @Override
+ public void setWorkModeEnabled(boolean enabled) {
+
+ }
+
+ @Override
+ public boolean hasActiveProfile() {
+ return false;
+ }
+
+ @Override
+ public boolean isWorkModeEnabled() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
new file mode 100644
index 0000000..fcfe9aa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
@@ -0,0 +1,78 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import com.android.settingslib.net.DataUsageController;
+import com.android.systemui.statusbar.policy.DataSaverController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+
+public class FakeNetworkController extends BaseLeakChecker<SignalCallback>
+ implements NetworkController {
+
+ private final FakeDataSaverController mDataSaverController;
+ private final BaseLeakChecker<EmergencyListener> mEmergencyChecker;
+
+ public FakeNetworkController(LeakCheckedTest test) {
+ super(test, "network");
+ mDataSaverController = new FakeDataSaverController(test);
+ mEmergencyChecker = new BaseLeakChecker<EmergencyListener>(test, "emergency");
+ }
+
+ @Override
+ public void addEmergencyListener(EmergencyListener listener) {
+ mEmergencyChecker.addCallback(listener);
+ }
+
+ @Override
+ public void removeEmergencyListener(EmergencyListener listener) {
+ mEmergencyChecker.removeCallback(listener);
+ }
+
+ @Override
+ public DataSaverController getDataSaverController() {
+ return mDataSaverController;
+ }
+
+ @Override
+ public boolean hasMobileDataFeature() {
+ return false;
+ }
+
+ @Override
+ public void setWifiEnabled(boolean enabled) {
+
+ }
+
+ @Override
+ public void onUserSwitched(int newUserId) {
+
+ }
+
+ @Override
+ public AccessPointController getAccessPointController() {
+ return null;
+ }
+
+ @Override
+ public DataUsageController getMobileDataController() {
+ return null;
+ }
+
+ @Override
+ public boolean hasVoiceCallingFeature() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNextAlarmController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNextAlarmController.java
new file mode 100644
index 0000000..707fc4b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNextAlarmController.java
@@ -0,0 +1,26 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
+
+public class FakeNextAlarmController extends BaseLeakChecker<NextAlarmChangeCallback>
+ implements NextAlarmController {
+
+ public FakeNextAlarmController(LeakCheckedTest test) {
+ super(test, "alarm");
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
new file mode 100644
index 0000000..00e2404
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
@@ -0,0 +1,50 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
+
+public class FakeRotationLockController extends BaseLeakChecker<RotationLockControllerCallback>
+ implements RotationLockController {
+ public FakeRotationLockController(LeakCheckedTest test) {
+ super(test, "rotation");
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+
+ }
+
+ @Override
+ public int getRotationLockOrientation() {
+ return 0;
+ }
+
+ @Override
+ public boolean isRotationLockAffordanceVisible() {
+ return false;
+ }
+
+ @Override
+ public boolean isRotationLocked() {
+ return false;
+ }
+
+ @Override
+ public void setRotationLocked(boolean locked) {
+
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeSecurityController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeSecurityController.java
new file mode 100644
index 0000000..331df58
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeSecurityController.java
@@ -0,0 +1,80 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.SecurityController.SecurityControllerCallback;
+
+public class FakeSecurityController extends BaseLeakChecker<SecurityControllerCallback>
+ implements SecurityController {
+ public FakeSecurityController(LeakCheckedTest test) {
+ super(test, "security");
+ }
+
+ @Override
+ public boolean isDeviceManaged() {
+ return false;
+ }
+
+ @Override
+ public boolean hasProfileOwner() {
+ return false;
+ }
+
+ @Override
+ public String getDeviceOwnerName() {
+ return null;
+ }
+
+ @Override
+ public String getProfileOwnerName() {
+ return null;
+ }
+
+ @Override
+ public CharSequence getDeviceOwnerOrganizationName() {
+ return null;
+ }
+
+ @Override
+ public boolean isVpnEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isVpnRestricted() {
+ return false;
+ }
+
+ @Override
+ public boolean isVpnBranded() {
+ return false;
+ }
+
+ @Override
+ public String getPrimaryVpnName() {
+ return null;
+ }
+
+ @Override
+ public String getProfileVpnName() {
+ return null;
+ }
+
+ @Override
+ public void onUserSwitched(int newUserId) {
+
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeUserInfoController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeUserInfoController.java
new file mode 100644
index 0000000..578b310
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeUserInfoController.java
@@ -0,0 +1,30 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
+
+public class FakeUserInfoController extends BaseLeakChecker<OnUserInfoChangedListener>
+ implements UserInfoController {
+ public FakeUserInfoController(LeakCheckedTest test) {
+ super(test, "user_info");
+ }
+
+ @Override
+ public void reloadUserInfo() {
+
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java
new file mode 100644
index 0000000..13ea385
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java
@@ -0,0 +1,84 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import android.content.ComponentName;
+import android.net.Uri;
+import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenModeConfig.ZenRule;
+
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.policy.ZenModeController.Callback;
+
+public class FakeZenModeController extends BaseLeakChecker<Callback> implements ZenModeController {
+ public FakeZenModeController(LeakCheckedTest test) {
+ super(test, "zen");
+ }
+
+ @Override
+ public void setZen(int zen, Uri conditionId, String reason) {
+
+ }
+
+ @Override
+ public int getZen() {
+ return 0;
+ }
+
+ @Override
+ public ZenRule getManualRule() {
+ return null;
+ }
+
+ @Override
+ public ZenModeConfig getConfig() {
+ return null;
+ }
+
+ @Override
+ public long getNextAlarm() {
+ return 0;
+ }
+
+ @Override
+ public void setUserId(int userId) {
+
+ }
+
+ @Override
+ public boolean isZenAvailable() {
+ return false;
+ }
+
+ @Override
+ public ComponentName getEffectsSuppressor() {
+ return null;
+ }
+
+ @Override
+ public boolean isCountdownConditionSupported() {
+ return false;
+ }
+
+ @Override
+ public int getCurrentUser() {
+ return 0;
+ }
+
+ @Override
+ public boolean isVolumeRestricted() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java
new file mode 100644
index 0000000..728ed60
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+
+import android.util.ArrayMap;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.ManagedProfileController;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CallbackController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Base class for tests to check if receivers are left registered, services bound, or other
+ * listeners listening.
+ */
+public abstract class LeakCheckedTest extends SysuiTestCase {
+ private static final String TAG = "LeakCheckedTest";
+
+ private final Map<String, Tracker> mTrackers = new HashMap<>();
+ private final Map<Class, Object> mLeakCheckers = new ArrayMap<>();
+
+ @Rule
+ public TestWatcher successWatcher = new TestWatcher() {
+ @Override
+ protected void succeeded(Description description) {
+ verify();
+ }
+ };
+
+ public <T> T getLeakChecker(Class<T> cls) {
+ Object obj = mLeakCheckers.get(cls);
+ if (obj == null) {
+ // Lazy create checkers so we only have the ones we need.
+ if (cls == BluetoothController.class) {
+ obj = new FakeBluetoothController(this);
+ } else if (cls == LocationController.class) {
+ obj = new FakeLocationController(this);
+ } else if (cls == RotationLockController.class) {
+ obj = new FakeRotationLockController(this);
+ } else if (cls == ZenModeController.class) {
+ obj = new FakeZenModeController(this);
+ } else if (cls == CastController.class) {
+ obj = new FakeCastController(this);
+ } else if (cls == HotspotController.class) {
+ obj = new FakeHotspotController(this);
+ } else if (cls == FlashlightController.class) {
+ obj = new FakeFlashlightController(this);
+ } else if (cls == UserInfoController.class) {
+ obj = new FakeUserInfoController(this);
+ } else if (cls == KeyguardMonitor.class) {
+ obj = new FakeKeyguardMonitor(this);
+ } else if (cls == BatteryController.class) {
+ obj = new FakeBatteryController(this);
+ } else if (cls == SecurityController.class) {
+ obj = new FakeSecurityController(this);
+ } else if (cls == ManagedProfileController.class) {
+ obj = new FakeManagedProfileController(this);
+ } else if (cls == NextAlarmController.class) {
+ obj = new FakeNextAlarmController(this);
+ } else if (cls == NetworkController.class) {
+ obj = new FakeNetworkController(this);
+ } else {
+ Assert.fail(cls.getName() + " is not supported by LeakCheckedTest yet");
+ }
+ mLeakCheckers.put(cls, obj);
+ }
+ return (T) obj;
+ }
+
+ @Override
+ public Tracker getTracker(String tag) {
+ Tracker t = mTrackers.get(tag);
+ if (t == null) {
+ t = new Tracker();
+ mTrackers.put(tag, t);
+ }
+ return t;
+ }
+
+ public void verify() {
+ mTrackers.values().forEach(Tracker::verify);
+ }
+
+ public <T extends CallbackController> T addListening(T mock, Class<T> cls, String tag) {
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ getTracker(tag).getLeakInfo(invocation.getArguments()[0])
+ .addAllocation(new Throwable());
+ return null;
+ }
+ }).when(mock).addCallback(any());
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ getTracker(tag).getLeakInfo(invocation.getArguments()[0]).clearAllocations();
+ return null;
+ }
+ }).when(mock).removeCallback(any());
+ mLeakCheckers.put(cls, mock);
+ return mock;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakInfo.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakInfo.java
new file mode 100644
index 0000000..1d016fb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakInfo.java
@@ -0,0 +1,53 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import android.util.Log;
+
+import org.junit.Assert;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public class LeakInfo {
+ private static final String TAG = "LeakInfo";
+ private List<Throwable> mThrowables = new ArrayList<>();
+
+ LeakInfo() {
+ }
+
+ public void addAllocation(Throwable t) {
+ // TODO: Drop off the first element in the stack trace here to have a cleaner stack.
+ mThrowables.add(t);
+ }
+
+ public void clearAllocations() {
+ mThrowables.clear();
+ }
+
+ void verify() {
+ if (mThrowables.size() == 0) return;
+ Log.e(TAG, "Listener or binding not properly released");
+ for (Throwable t : mThrowables) {
+ Log.e(TAG, "Allocation found", t);
+ }
+ StringWriter writer = new StringWriter();
+ mThrowables.get(0).printStackTrace(new PrintWriter(writer));
+ Assert.fail("Listener or binding not properly released\n"
+ + writer.toString());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/Tracker.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/Tracker.java
new file mode 100644
index 0000000..26ffd10
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/Tracker.java
@@ -0,0 +1,38 @@
+/*
+ * 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.systemui.utils.leaks;
+
+import android.util.ArrayMap;
+
+import com.android.systemui.utils.leaks.LeakInfo;
+
+import java.util.Map;
+
+public class Tracker {
+ private Map<Object, LeakInfo> mObjects = new ArrayMap<>();
+
+ public LeakInfo getLeakInfo(Object object) {
+ LeakInfo leakInfo = mObjects.get(object);
+ if (leakInfo == null) {
+ leakInfo = new LeakInfo();
+ mObjects.put(object, leakInfo);
+ }
+ return leakInfo;
+ }
+
+ void verify() {
+ mObjects.values().forEach(LeakInfo::verify);
+ }
+}