From 9abca5e9f88c47579f8334c6c48741a259185b9b Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Fri, 11 Nov 2016 16:18:14 -0500 Subject: [PATCH] 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 --- .../phone/ManagedProfileController.java | 126 +------- .../phone/ManagedProfileControllerImpl.java | 142 +++++++++ .../statusbar/phone/PhoneStatusBar.java | 28 +- .../systemui/statusbar/phone/QSTileHost.java | 2 +- .../statusbar/phone/QuickStatusBarHeader.java | 9 +- .../statusbar/policy/DataSaverController.java | 84 +---- .../policy/DataSaverControllerImpl.java | 101 ++++++ .../policy/FlashlightController.java | 252 +-------------- .../policy/FlashlightControllerImpl.java | 253 +++++++++++++++ .../statusbar/policy/KeyguardMonitor.java | 122 +------- .../statusbar/policy/KeyguardMonitorImpl.java | 122 ++++++++ .../policy/NetworkControllerImpl.java | 2 +- .../statusbar/policy/NextAlarmController.java | 76 +---- .../policy/NextAlarmControllerImpl.java | 82 +++++ .../statusbar/policy/UserInfoController.java | 223 +------------- .../policy/UserInfoControllerImpl.java | 229 ++++++++++++++ .../android/systemui/tuner/TunerService.java | 4 + .../android/systemui/FragmentTestCase.java | 4 +- .../com/android/systemui/LeakCheckedTest.java | 287 ------------------ .../com/android/systemui/SysuiTestCase.java | 10 +- .../android/systemui/qs/QSFragmentTest.java | 5 +- .../systemui/utils/TestableContext.java | 85 +++++- .../systemui/utils/leaks/BaseLeakChecker.java | 40 +++ .../utils/leaks/FakeBatteryController.java | 50 +++ .../utils/leaks/FakeBluetoothController.java | 84 +++++ .../utils/leaks/FakeCastController.java | 51 ++++ .../utils/leaks/FakeDataSaverController.java | 35 +++ .../utils/leaks/FakeFlashlightController.java | 45 +++ .../utils/leaks/FakeHotspotController.java | 40 +++ .../utils/leaks/FakeKeyguardMonitor.java | 51 ++++ .../utils/leaks/FakeLocationController.java | 35 +++ .../leaks/FakeManagedProfileController.java | 40 +++ .../utils/leaks/FakeNetworkController.java | 78 +++++ .../utils/leaks/FakeNextAlarmController.java | 26 ++ .../leaks/FakeRotationLockController.java | 50 +++ .../utils/leaks/FakeSecurityController.java | 80 +++++ .../utils/leaks/FakeUserInfoController.java | 30 ++ .../utils/leaks/FakeZenModeController.java | 84 +++++ .../systemui/utils/leaks/LeakCheckedTest.java | 140 +++++++++ .../systemui/utils/leaks/LeakInfo.java | 53 ++++ .../android/systemui/utils/leaks/Tracker.java | 38 +++ 41 files changed, 2154 insertions(+), 1144 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverControllerImpl.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/LeakCheckedTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/BaseLeakChecker.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeCastController.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeDataSaverController.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeFlashlightController.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeLocationController.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeManagedProfileController.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNextAlarmController.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeSecurityController.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeUserInfoController.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakInfo.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/Tracker.java diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java index 1a46815c99e7e..4969a1c9a20b9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java @@ -14,134 +14,16 @@ package com.android.systemui.statusbar.phone; -import android.app.ActivityManager; -import android.app.StatusBarManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.UserInfo; -import android.os.UserHandle; -import android.os.UserManager; - import com.android.systemui.statusbar.phone.ManagedProfileController.Callback; import com.android.systemui.statusbar.policy.CallbackController; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; +public interface ManagedProfileController extends CallbackController { -public class ManagedProfileController implements CallbackController { + void setWorkModeEnabled(boolean enabled); - private final List mCallbacks = new ArrayList<>(); + boolean hasActiveProfile(); - private final Context mContext; - private final UserManager mUserManager; - private final LinkedList mProfiles; - private boolean mListening; - private int mCurrentUser; - - public ManagedProfileController(QSTileHost host) { - mContext = host.getContext(); - mUserManager = UserManager.get(mContext); - mProfiles = new LinkedList(); - } - - public void addCallback(Callback callback) { - mCallbacks.add(callback); - if (mCallbacks.size() == 1) { - setListening(true); - } - callback.onManagedProfileChanged(); - } - - public void removeCallback(Callback callback) { - if (mCallbacks.remove(callback) && mCallbacks.size() == 0) { - setListening(false); - } - } - - public void setWorkModeEnabled(boolean enableWorkMode) { - synchronized (mProfiles) { - for (UserInfo ui : mProfiles) { - if (enableWorkMode) { - if (!mUserManager.trySetQuietModeDisabled(ui.id, null)) { - StatusBarManager statusBarManager = (StatusBarManager) mContext - .getSystemService(android.app.Service.STATUS_BAR_SERVICE); - statusBarManager.collapsePanels(); - } - } else { - mUserManager.setQuietModeEnabled(ui.id, true); - } - } - } - } - - private void reloadManagedProfiles() { - synchronized (mProfiles) { - boolean hadProfile = mProfiles.size() > 0; - int user = ActivityManager.getCurrentUser(); - mProfiles.clear(); - - for (UserInfo ui : mUserManager.getEnabledProfiles(user)) { - if (ui.isManagedProfile()) { - mProfiles.add(ui); - } - } - if (mProfiles.size() == 0 && hadProfile && (user == mCurrentUser)) { - for (Callback callback : mCallbacks) { - callback.onManagedProfileRemoved(); - } - } - mCurrentUser = user; - } - } - - public boolean hasActiveProfile() { - if (!mListening) reloadManagedProfiles(); - synchronized (mProfiles) { - return mProfiles.size() > 0; - } - } - - public boolean isWorkModeEnabled() { - if (!mListening) reloadManagedProfiles(); - synchronized (mProfiles) { - for (UserInfo ui : mProfiles) { - if (ui.isQuietModeEnabled()) { - return false; - } - } - return true; - } - } - - private void setListening(boolean listening) { - mListening = listening; - if (listening) { - reloadManagedProfiles(); - - final IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_USER_SWITCHED); - filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); - filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); - filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); - filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); - mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null); - } else { - mContext.unregisterReceiver(mReceiver); - } - } - - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - reloadManagedProfiles(); - for (Callback callback : mCallbacks) { - callback.onManagedProfileChanged(); - } - } - }; + boolean isWorkModeEnabled(); public interface Callback { void onManagedProfileChanged(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java new file mode 100644 index 0000000000000..fc33ace73f7f9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java @@ -0,0 +1,142 @@ +/* + * 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.statusbar.phone; + +import android.app.ActivityManager; +import android.app.StatusBarManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.UserInfo; +import android.os.UserHandle; +import android.os.UserManager; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +public class ManagedProfileControllerImpl implements ManagedProfileController { + + private final List mCallbacks = new ArrayList<>(); + + private final Context mContext; + private final UserManager mUserManager; + private final LinkedList mProfiles; + private boolean mListening; + private int mCurrentUser; + + public ManagedProfileControllerImpl(QSTileHost host) { + mContext = host.getContext(); + mUserManager = UserManager.get(mContext); + mProfiles = new LinkedList(); + } + + public void addCallback(Callback callback) { + mCallbacks.add(callback); + if (mCallbacks.size() == 1) { + setListening(true); + } + callback.onManagedProfileChanged(); + } + + public void removeCallback(Callback callback) { + if (mCallbacks.remove(callback) && mCallbacks.size() == 0) { + setListening(false); + } + } + + public void setWorkModeEnabled(boolean enableWorkMode) { + synchronized (mProfiles) { + for (UserInfo ui : mProfiles) { + if (enableWorkMode) { + if (!mUserManager.trySetQuietModeDisabled(ui.id, null)) { + StatusBarManager statusBarManager = (StatusBarManager) mContext + .getSystemService(android.app.Service.STATUS_BAR_SERVICE); + statusBarManager.collapsePanels(); + } + } else { + mUserManager.setQuietModeEnabled(ui.id, true); + } + } + } + } + + private void reloadManagedProfiles() { + synchronized (mProfiles) { + boolean hadProfile = mProfiles.size() > 0; + int user = ActivityManager.getCurrentUser(); + mProfiles.clear(); + + for (UserInfo ui : mUserManager.getEnabledProfiles(user)) { + if (ui.isManagedProfile()) { + mProfiles.add(ui); + } + } + if (mProfiles.size() == 0 && hadProfile && (user == mCurrentUser)) { + for (Callback callback : mCallbacks) { + callback.onManagedProfileRemoved(); + } + } + mCurrentUser = user; + } + } + + public boolean hasActiveProfile() { + if (!mListening) reloadManagedProfiles(); + synchronized (mProfiles) { + return mProfiles.size() > 0; + } + } + + public boolean isWorkModeEnabled() { + if (!mListening) reloadManagedProfiles(); + synchronized (mProfiles) { + for (UserInfo ui : mProfiles) { + if (ui.isQuietModeEnabled()) { + return false; + } + } + return true; + } + } + + private void setListening(boolean listening) { + mListening = listening; + if (listening) { + reloadManagedProfiles(); + + final IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_USER_SWITCHED); + filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); + filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); + filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); + filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); + mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null); + } else { + mContext.unregisterReceiver(mReceiver); + } + } + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + reloadManagedProfiles(); + for (Callback callback : mCallbacks) { + callback.onManagedProfileChanged(); + } + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 2c613581bf290..4579ce69b0665 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -22,6 +22,7 @@ import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.app.StatusBarManager.windowStateToString; + import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE; @@ -83,8 +84,8 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; -import android.os.Trace; import android.os.SystemProperties; +import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.os.Vibrator; @@ -123,13 +124,13 @@ import com.android.keyguard.KeyguardHostView.OnDismissAction; import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.keyguard.LatencyTracker; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.BatteryMeterView; import com.android.systemui.DemoMode; import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; import com.android.systemui.Interpolators; -import com.android.keyguard.LatencyTracker; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.SystemUIFactory; @@ -178,19 +179,20 @@ import com.android.systemui.statusbar.policy.BluetoothControllerImpl; import com.android.systemui.statusbar.policy.BrightnessMirrorController; import com.android.systemui.statusbar.policy.CastControllerImpl; import com.android.systemui.statusbar.policy.EncryptionHelper; -import com.android.systemui.statusbar.policy.FlashlightController; +import com.android.systemui.statusbar.policy.FlashlightControllerImpl; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.HotspotControllerImpl; -import com.android.systemui.statusbar.policy.KeyguardMonitor; +import com.android.systemui.statusbar.policy.KeyguardMonitorImpl; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.LocationControllerImpl; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkControllerImpl; import com.android.systemui.statusbar.policy.NextAlarmController; +import com.android.systemui.statusbar.policy.NextAlarmControllerImpl; import com.android.systemui.statusbar.policy.PreviewInflater; import com.android.systemui.statusbar.policy.RotationLockControllerImpl; import com.android.systemui.statusbar.policy.SecurityControllerImpl; -import com.android.systemui.statusbar.policy.UserInfoController; +import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; @@ -319,15 +321,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, NetworkControllerImpl mNetworkController; HotspotControllerImpl mHotspotController; RotationLockControllerImpl mRotationLockController; - UserInfoController mUserInfoController; + UserInfoControllerImpl mUserInfoController; protected ZenModeController mZenModeController; CastControllerImpl mCastController; VolumeComponent mVolumeComponent; KeyguardUserSwitcher mKeyguardUserSwitcher; - FlashlightController mFlashlightController; + FlashlightControllerImpl mFlashlightController; protected UserSwitcherController mUserSwitcherController; - NextAlarmController mNextAlarmController; - protected KeyguardMonitor mKeyguardMonitor; + NextAlarmControllerImpl mNextAlarmController; + protected KeyguardMonitorImpl mKeyguardMonitor; BrightnessMirrorController mBrightnessMirrorController; AccessibilityController mAccessibilityController; protected FingerprintUnlockController mFingerprintUnlockController; @@ -895,7 +897,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) { mRotationLockController = new RotationLockControllerImpl(mContext); } - mUserInfoController = new UserInfoController(mContext); + mUserInfoController = new UserInfoControllerImpl(mContext); mVolumeComponent = getComponent(VolumeComponent.class); if (mVolumeComponent != null) { mZenModeController = mVolumeComponent.getZenController(); @@ -906,16 +908,16 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, initSignalCluster(mKeyguardStatusBar); initEmergencyCryptkeeperText(); - mFlashlightController = new FlashlightController(mContext); + mFlashlightController = new FlashlightControllerImpl(mContext); mKeyguardBottomArea.setFlashlightController(mFlashlightController); mKeyguardBottomArea.setPhoneStatusBar(this); mKeyguardBottomArea.setUserSetupComplete(mUserSetup); mAccessibilityController = new AccessibilityController(mContext); mKeyguardBottomArea.setAccessibilityController(mAccessibilityController); - mNextAlarmController = new NextAlarmController(mContext); + mNextAlarmController = new NextAlarmControllerImpl(mContext); mLightStatusBarController = new LightStatusBarController(mIconController, mBatteryController); - mKeyguardMonitor = new KeyguardMonitor(mContext); + mKeyguardMonitor = new KeyguardMonitorImpl(mContext); mUserSwitcherController = createUserSwitcherController(); if (UserManager.get(mContext).isUserSwitcherEnabled()) { createUserSwitcher(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java index 8fd6bbfacba56..567ab3b5966d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -143,7 +143,7 @@ public class QSTileHost implements QSTile.Host, Tunable { mBattery = battery; mIconController = iconController; mNextAlarmController = nextAlarmController; - mProfileController = new ManagedProfileController(this); + mProfileController = new ManagedProfileControllerImpl(this); mHandlerThread = new HandlerThread(QSTileHost.class.getSimpleName(), Process.THREAD_PRIORITY_BACKGROUND); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java index 28aed878b5067..9ab4d77c83c7f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java @@ -235,11 +235,18 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD); } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mHost.getUserInfoController().addCallback(this); + } + @Override protected void onDetachedFromWindow() { setListening(false); mHost.getUserInfoController().removeCallback(this); mHost.getNetworkController().removeEmergencyListener(this); + mHost.getUserInfoController().removeCallback(this); super.onDetachedFromWindow(); } @@ -368,7 +375,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements } public void setUserInfoController(UserInfoController userInfoController) { - userInfoController.addCallback(this); + // Don't care } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java index e5f1e68f81843..0df7859e6ced4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java @@ -14,92 +14,14 @@ package com.android.systemui.statusbar.policy; -import android.content.Context; -import android.net.INetworkPolicyListener; -import android.net.NetworkPolicyManager; -import android.os.Handler; -import android.os.Looper; -import android.os.RemoteException; - import com.android.systemui.statusbar.policy.DataSaverController.Listener; -import java.util.ArrayList; +public interface DataSaverController extends CallbackController { -public class DataSaverController implements CallbackController { - - private final Handler mHandler = new Handler(Looper.getMainLooper()); - private final ArrayList mListeners = new ArrayList<>(); - private final NetworkPolicyManager mPolicyManager; - - public DataSaverController(Context context) { - mPolicyManager = NetworkPolicyManager.from(context); - } - - private void handleRestrictBackgroundChanged(boolean isDataSaving) { - synchronized (mListeners) { - for (int i = 0; i < mListeners.size(); i++) { - mListeners.get(i).onDataSaverChanged(isDataSaving); - } - } - } - - public void addCallback(Listener listener) { - synchronized (mListeners) { - mListeners.add(listener); - if (mListeners.size() == 1) { - mPolicyManager.registerListener(mPolicyListener); - } - } - listener.onDataSaverChanged(isDataSaverEnabled()); - } - - public void removeCallback(Listener listener) { - synchronized (mListeners) { - mListeners.remove(listener); - if (mListeners.size() == 0) { - mPolicyManager.unregisterListener(mPolicyListener); - } - } - } - - public boolean isDataSaverEnabled() { - return mPolicyManager.getRestrictBackground(); - } - - public void setDataSaverEnabled(boolean enabled) { - mPolicyManager.setRestrictBackground(enabled); - try { - mPolicyListener.onRestrictBackgroundChanged(enabled); - } catch (RemoteException e) { - } - } - - private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { - @Override - public void onUidRulesChanged(int uid, int uidRules) throws RemoteException { - } - - @Override - public void onMeteredIfacesChanged(String[] strings) throws RemoteException { - } - - @Override - public void onRestrictBackgroundChanged(final boolean isDataSaving) throws RemoteException { - mHandler.post(new Runnable() { - @Override - public void run() { - handleRestrictBackgroundChanged(isDataSaving); - } - }); - } - - @Override - public void onUidPoliciesChanged(int uid, int uidPolicies) throws RemoteException { - } - }; + boolean isDataSaverEnabled(); + void setDataSaverEnabled(boolean enabled); public interface Listener { void onDataSaverChanged(boolean isDataSaving); } - } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverControllerImpl.java new file mode 100644 index 0000000000000..2951943404b34 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverControllerImpl.java @@ -0,0 +1,101 @@ +/* + * 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.statusbar.policy; + +import android.content.Context; +import android.net.INetworkPolicyListener; +import android.net.NetworkPolicyManager; +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; + +import com.android.systemui.statusbar.policy.DataSaverController.Listener; + +import java.util.ArrayList; + +public class DataSaverControllerImpl implements DataSaverController { + + private final Handler mHandler = new Handler(Looper.getMainLooper()); + private final ArrayList mListeners = new ArrayList<>(); + private final NetworkPolicyManager mPolicyManager; + + public DataSaverControllerImpl(Context context) { + mPolicyManager = NetworkPolicyManager.from(context); + } + + private void handleRestrictBackgroundChanged(boolean isDataSaving) { + synchronized (mListeners) { + for (int i = 0; i < mListeners.size(); i++) { + mListeners.get(i).onDataSaverChanged(isDataSaving); + } + } + } + + public void addCallback(Listener listener) { + synchronized (mListeners) { + mListeners.add(listener); + if (mListeners.size() == 1) { + mPolicyManager.registerListener(mPolicyListener); + } + } + listener.onDataSaverChanged(isDataSaverEnabled()); + } + + public void removeCallback(Listener listener) { + synchronized (mListeners) { + mListeners.remove(listener); + if (mListeners.size() == 0) { + mPolicyManager.unregisterListener(mPolicyListener); + } + } + } + + public boolean isDataSaverEnabled() { + return mPolicyManager.getRestrictBackground(); + } + + public void setDataSaverEnabled(boolean enabled) { + mPolicyManager.setRestrictBackground(enabled); + try { + mPolicyListener.onRestrictBackgroundChanged(enabled); + } catch (RemoteException e) { + } + } + + private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { + @Override + public void onUidRulesChanged(int uid, int uidRules) throws RemoteException { + } + + @Override + public void onMeteredIfacesChanged(String[] strings) throws RemoteException { + } + + @Override + public void onRestrictBackgroundChanged(final boolean isDataSaving) throws RemoteException { + mHandler.post(new Runnable() { + @Override + public void run() { + handleRestrictBackgroundChanged(isDataSaving); + } + }); + } + + @Override + public void onUidPoliciesChanged(int uid, int uidPolicies) throws RemoteException { + } + }; + +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java index 0f77b03b17117..6023f3ee17c0c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java @@ -1,255 +1,27 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * 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 * - * 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 + * 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 android.content.Context; -import android.content.pm.PackageManager; -import android.hardware.camera2.CameraAccessException; -import android.hardware.camera2.CameraCharacteristics; -import android.hardware.camera2.CameraManager; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Process; -import android.text.TextUtils; -import android.util.Log; - import com.android.systemui.statusbar.policy.FlashlightController.FlashlightListener; -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.lang.ref.WeakReference; -import java.util.ArrayList; +public interface FlashlightController extends CallbackController { -/** - * Manages the flashlight. - */ -public class FlashlightController implements CallbackController { - - private static final String TAG = "FlashlightController"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private static final int DISPATCH_ERROR = 0; - private static final int DISPATCH_CHANGED = 1; - private static final int DISPATCH_AVAILABILITY_CHANGED = 2; - - private final CameraManager mCameraManager; - private final Context mContext; - /** Call {@link #ensureHandler()} before using */ - private Handler mHandler; - - /** Lock on mListeners when accessing */ - private final ArrayList> mListeners = new ArrayList<>(1); - - /** Lock on {@code this} when accessing */ - private boolean mFlashlightEnabled; - - private String mCameraId; - private boolean mTorchAvailable; - - public FlashlightController(Context context) { - mContext = context; - mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE); - - tryInitCamera(); - } - - private void tryInitCamera() { - try { - mCameraId = getCameraId(); - } catch (Throwable e) { - Log.e(TAG, "Couldn't initialize.", e); - return; - } - - if (mCameraId != null) { - ensureHandler(); - mCameraManager.registerTorchCallback(mTorchCallback, mHandler); - } - } - - public void setFlashlight(boolean enabled) { - boolean pendingError = false; - synchronized (this) { - if (mCameraId == null) return; - if (mFlashlightEnabled != enabled) { - mFlashlightEnabled = enabled; - try { - mCameraManager.setTorchMode(mCameraId, enabled); - } catch (CameraAccessException e) { - Log.e(TAG, "Couldn't set torch mode", e); - mFlashlightEnabled = false; - pendingError = true; - } - } - } - dispatchModeChanged(mFlashlightEnabled); - if (pendingError) { - dispatchError(); - } - } - - public boolean hasFlashlight() { - return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH); - } - - public synchronized boolean isEnabled() { - return mFlashlightEnabled; - } - - public synchronized boolean isAvailable() { - return mTorchAvailable; - } - - public void addCallback(FlashlightListener l) { - synchronized (mListeners) { - if (mCameraId == null) { - tryInitCamera(); - } - cleanUpListenersLocked(l); - mListeners.add(new WeakReference<>(l)); - } - } - - public void removeCallback(FlashlightListener l) { - synchronized (mListeners) { - cleanUpListenersLocked(l); - } - } - - private synchronized void ensureHandler() { - if (mHandler == null) { - HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND); - thread.start(); - mHandler = new Handler(thread.getLooper()); - } - } - - private String getCameraId() throws CameraAccessException { - String[] ids = mCameraManager.getCameraIdList(); - for (String id : ids) { - CameraCharacteristics c = mCameraManager.getCameraCharacteristics(id); - Boolean flashAvailable = c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE); - Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING); - if (flashAvailable != null && flashAvailable - && lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_BACK) { - return id; - } - } - return null; - } - - private void dispatchModeChanged(boolean enabled) { - dispatchListeners(DISPATCH_CHANGED, enabled); - } - - private void dispatchError() { - dispatchListeners(DISPATCH_CHANGED, false /* argument (ignored) */); - } - - private void dispatchAvailabilityChanged(boolean available) { - dispatchListeners(DISPATCH_AVAILABILITY_CHANGED, available); - } - - private void dispatchListeners(int message, boolean argument) { - synchronized (mListeners) { - final int N = mListeners.size(); - boolean cleanup = false; - for (int i = 0; i < N; i++) { - FlashlightListener l = mListeners.get(i).get(); - if (l != null) { - if (message == DISPATCH_ERROR) { - l.onFlashlightError(); - } else if (message == DISPATCH_CHANGED) { - l.onFlashlightChanged(argument); - } else if (message == DISPATCH_AVAILABILITY_CHANGED) { - l.onFlashlightAvailabilityChanged(argument); - } - } else { - cleanup = true; - } - } - if (cleanup) { - cleanUpListenersLocked(null); - } - } - } - - private void cleanUpListenersLocked(FlashlightListener listener) { - for (int i = mListeners.size() - 1; i >= 0; i--) { - FlashlightListener found = mListeners.get(i).get(); - if (found == null || found == listener) { - mListeners.remove(i); - } - } - } - - private final CameraManager.TorchCallback mTorchCallback = - new CameraManager.TorchCallback() { - - @Override - public void onTorchModeUnavailable(String cameraId) { - if (TextUtils.equals(cameraId, mCameraId)) { - setCameraAvailable(false); - } - } - - @Override - public void onTorchModeChanged(String cameraId, boolean enabled) { - if (TextUtils.equals(cameraId, mCameraId)) { - setCameraAvailable(true); - setTorchMode(enabled); - } - } - - private void setCameraAvailable(boolean available) { - boolean changed; - synchronized (FlashlightController.this) { - changed = mTorchAvailable != available; - mTorchAvailable = available; - } - if (changed) { - if (DEBUG) Log.d(TAG, "dispatchAvailabilityChanged(" + available + ")"); - dispatchAvailabilityChanged(available); - } - } - - private void setTorchMode(boolean enabled) { - boolean changed; - synchronized (FlashlightController.this) { - changed = mFlashlightEnabled != enabled; - mFlashlightEnabled = enabled; - } - if (changed) { - if (DEBUG) Log.d(TAG, "dispatchModeChanged(" + enabled + ")"); - dispatchModeChanged(enabled); - } - } - }; - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("FlashlightController state:"); - - pw.print(" mCameraId="); - pw.println(mCameraId); - pw.print(" mFlashlightEnabled="); - pw.println(mFlashlightEnabled); - pw.print(" mTorchAvailable="); - pw.println(mTorchAvailable); - } + boolean hasFlashlight(); + void setFlashlight(boolean newState); + boolean isAvailable(); + boolean isEnabled(); public interface FlashlightListener { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java new file mode 100644 index 0000000000000..008d837da51c4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2014 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 android.content.Context; +import android.content.pm.PackageManager; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraManager; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Process; +import android.text.TextUtils; +import android.util.Log; + +import com.android.systemui.statusbar.policy.FlashlightController.FlashlightListener; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.lang.ref.WeakReference; +import java.util.ArrayList; + +/** + * Manages the flashlight. + */ +public class FlashlightControllerImpl implements FlashlightController { + + private static final String TAG = "FlashlightController"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private static final int DISPATCH_ERROR = 0; + private static final int DISPATCH_CHANGED = 1; + private static final int DISPATCH_AVAILABILITY_CHANGED = 2; + + private final CameraManager mCameraManager; + private final Context mContext; + /** Call {@link #ensureHandler()} before using */ + private Handler mHandler; + + /** Lock on mListeners when accessing */ + private final ArrayList> mListeners = new ArrayList<>(1); + + /** Lock on {@code this} when accessing */ + private boolean mFlashlightEnabled; + + private String mCameraId; + private boolean mTorchAvailable; + + public FlashlightControllerImpl(Context context) { + mContext = context; + mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE); + + tryInitCamera(); + } + + private void tryInitCamera() { + try { + mCameraId = getCameraId(); + } catch (Throwable e) { + Log.e(TAG, "Couldn't initialize.", e); + return; + } + + if (mCameraId != null) { + ensureHandler(); + mCameraManager.registerTorchCallback(mTorchCallback, mHandler); + } + } + + public void setFlashlight(boolean enabled) { + boolean pendingError = false; + synchronized (this) { + if (mCameraId == null) return; + if (mFlashlightEnabled != enabled) { + mFlashlightEnabled = enabled; + try { + mCameraManager.setTorchMode(mCameraId, enabled); + } catch (CameraAccessException e) { + Log.e(TAG, "Couldn't set torch mode", e); + mFlashlightEnabled = false; + pendingError = true; + } + } + } + dispatchModeChanged(mFlashlightEnabled); + if (pendingError) { + dispatchError(); + } + } + + public boolean hasFlashlight() { + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH); + } + + public synchronized boolean isEnabled() { + return mFlashlightEnabled; + } + + public synchronized boolean isAvailable() { + return mTorchAvailable; + } + + public void addCallback(FlashlightListener l) { + synchronized (mListeners) { + if (mCameraId == null) { + tryInitCamera(); + } + cleanUpListenersLocked(l); + mListeners.add(new WeakReference<>(l)); + } + } + + public void removeCallback(FlashlightListener l) { + synchronized (mListeners) { + cleanUpListenersLocked(l); + } + } + + private synchronized void ensureHandler() { + if (mHandler == null) { + HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + mHandler = new Handler(thread.getLooper()); + } + } + + private String getCameraId() throws CameraAccessException { + String[] ids = mCameraManager.getCameraIdList(); + for (String id : ids) { + CameraCharacteristics c = mCameraManager.getCameraCharacteristics(id); + Boolean flashAvailable = c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE); + Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING); + if (flashAvailable != null && flashAvailable + && lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_BACK) { + return id; + } + } + return null; + } + + private void dispatchModeChanged(boolean enabled) { + dispatchListeners(DISPATCH_CHANGED, enabled); + } + + private void dispatchError() { + dispatchListeners(DISPATCH_CHANGED, false /* argument (ignored) */); + } + + private void dispatchAvailabilityChanged(boolean available) { + dispatchListeners(DISPATCH_AVAILABILITY_CHANGED, available); + } + + private void dispatchListeners(int message, boolean argument) { + synchronized (mListeners) { + final int N = mListeners.size(); + boolean cleanup = false; + for (int i = 0; i < N; i++) { + FlashlightListener l = mListeners.get(i).get(); + if (l != null) { + if (message == DISPATCH_ERROR) { + l.onFlashlightError(); + } else if (message == DISPATCH_CHANGED) { + l.onFlashlightChanged(argument); + } else if (message == DISPATCH_AVAILABILITY_CHANGED) { + l.onFlashlightAvailabilityChanged(argument); + } + } else { + cleanup = true; + } + } + if (cleanup) { + cleanUpListenersLocked(null); + } + } + } + + private void cleanUpListenersLocked(FlashlightListener listener) { + for (int i = mListeners.size() - 1; i >= 0; i--) { + FlashlightListener found = mListeners.get(i).get(); + if (found == null || found == listener) { + mListeners.remove(i); + } + } + } + + private final CameraManager.TorchCallback mTorchCallback = + new CameraManager.TorchCallback() { + + @Override + public void onTorchModeUnavailable(String cameraId) { + if (TextUtils.equals(cameraId, mCameraId)) { + setCameraAvailable(false); + } + } + + @Override + public void onTorchModeChanged(String cameraId, boolean enabled) { + if (TextUtils.equals(cameraId, mCameraId)) { + setCameraAvailable(true); + setTorchMode(enabled); + } + } + + private void setCameraAvailable(boolean available) { + boolean changed; + synchronized (FlashlightControllerImpl.this) { + changed = mTorchAvailable != available; + mTorchAvailable = available; + } + if (changed) { + if (DEBUG) Log.d(TAG, "dispatchAvailabilityChanged(" + available + ")"); + dispatchAvailabilityChanged(available); + } + } + + private void setTorchMode(boolean enabled) { + boolean changed; + synchronized (FlashlightControllerImpl.this) { + changed = mFlashlightEnabled != enabled; + mFlashlightEnabled = enabled; + } + if (changed) { + if (DEBUG) Log.d(TAG, "dispatchModeChanged(" + enabled + ")"); + dispatchModeChanged(enabled); + } + } + }; + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("FlashlightController state:"); + + pw.print(" mCameraId="); + pw.println(mCameraId); + pw.print(" mFlashlightEnabled="); + pw.println(mFlashlightEnabled); + pw.print(" mTorchAvailable="); + pw.println(mTorchAvailable); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java index 0396613499100..de47267465cdd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java @@ -1,126 +1,28 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * 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 * - * 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. + * 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 android.app.ActivityManager; -import android.content.Context; -import android.os.RemoteException; -import android.view.WindowManagerGlobal; - -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.keyguard.KeyguardUpdateMonitorCallback; -import com.android.systemui.settings.CurrentUserTracker; import com.android.systemui.statusbar.policy.KeyguardMonitor.Callback; -import java.util.ArrayList; +public interface KeyguardMonitor extends CallbackController { -public class KeyguardMonitor extends KeyguardUpdateMonitorCallback - implements CallbackController { - - private final ArrayList mCallbacks = new ArrayList(); - - private final Context mContext; - private final CurrentUserTracker mUserTracker; - private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; - - private int mCurrentUser; - private boolean mShowing; - private boolean mSecure; - private boolean mOccluded; - private boolean mCanSkipBouncer; - - private boolean mListening; - - public KeyguardMonitor(Context context) { - mContext = context; - mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); - mUserTracker = new CurrentUserTracker(mContext) { - @Override - public void onUserSwitched(int newUserId) { - mCurrentUser = newUserId; - updateCanSkipBouncerState(); - } - }; - } - - public void addCallback(Callback callback) { - mCallbacks.add(callback); - if (mCallbacks.size() != 0 && !mListening) { - mListening = true; - mCurrentUser = ActivityManager.getCurrentUser(); - updateCanSkipBouncerState(); - mKeyguardUpdateMonitor.registerCallback(this); - mUserTracker.startTracking(); - } - } - - public void removeCallback(Callback callback) { - if (mCallbacks.remove(callback) && mCallbacks.size() == 0 && mListening) { - mListening = false; - mKeyguardUpdateMonitor.removeCallback(this); - mUserTracker.stopTracking(); - } - } - - public boolean isShowing() { - return mShowing; - } - - public boolean isSecure() { - return mSecure; - } - - public boolean isOccluded() { - return mOccluded; - } - - public boolean canSkipBouncer() { - return mCanSkipBouncer; - } - - public void notifyKeyguardState(boolean showing, boolean secure, boolean occluded) { - if (mShowing == showing && mSecure == secure && mOccluded == occluded) return; - mShowing = showing; - mSecure = secure; - mOccluded = occluded; - notifyKeyguardChanged(); - } - - @Override - public void onTrustChanged(int userId) { - updateCanSkipBouncerState(); - notifyKeyguardChanged(); - } - - public boolean isDeviceInteractive() { - return mKeyguardUpdateMonitor.isDeviceInteractive(); - } - - private void updateCanSkipBouncerState() { - mCanSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer(mCurrentUser); - } - - private void notifyKeyguardChanged() { - for (Callback callback : mCallbacks) { - callback.onKeyguardChanged(); - } - } + boolean isSecure(); + boolean canSkipBouncer(); + boolean isShowing(); public interface Callback { void onKeyguardChanged(); } -} \ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java new file mode 100644 index 0000000000000..769f93f88e14c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2014 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 android.app.ActivityManager; +import android.content.Context; +import android.os.RemoteException; +import android.view.WindowManagerGlobal; + +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.systemui.settings.CurrentUserTracker; +import com.android.systemui.statusbar.policy.KeyguardMonitor.Callback; + +import java.util.ArrayList; + +public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback + implements KeyguardMonitor { + + private final ArrayList mCallbacks = new ArrayList(); + + private final Context mContext; + private final CurrentUserTracker mUserTracker; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + + private int mCurrentUser; + private boolean mShowing; + private boolean mSecure; + private boolean mOccluded; + private boolean mCanSkipBouncer; + + private boolean mListening; + + public KeyguardMonitorImpl(Context context) { + mContext = context; + mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); + mUserTracker = new CurrentUserTracker(mContext) { + @Override + public void onUserSwitched(int newUserId) { + mCurrentUser = newUserId; + updateCanSkipBouncerState(); + } + }; + } + + public void addCallback(Callback callback) { + mCallbacks.add(callback); + if (mCallbacks.size() != 0 && !mListening) { + mListening = true; + mCurrentUser = ActivityManager.getCurrentUser(); + updateCanSkipBouncerState(); + mKeyguardUpdateMonitor.registerCallback(this); + mUserTracker.startTracking(); + } + } + + public void removeCallback(Callback callback) { + if (mCallbacks.remove(callback) && mCallbacks.size() == 0 && mListening) { + mListening = false; + mKeyguardUpdateMonitor.removeCallback(this); + mUserTracker.stopTracking(); + } + } + + public boolean isShowing() { + return mShowing; + } + + public boolean isSecure() { + return mSecure; + } + + public boolean isOccluded() { + return mOccluded; + } + + public boolean canSkipBouncer() { + return mCanSkipBouncer; + } + + public void notifyKeyguardState(boolean showing, boolean secure, boolean occluded) { + if (mShowing == showing && mSecure == secure && mOccluded == occluded) return; + mShowing = showing; + mSecure = secure; + mOccluded = occluded; + notifyKeyguardChanged(); + } + + @Override + public void onTrustChanged(int userId) { + updateCanSkipBouncerState(); + notifyKeyguardChanged(); + } + + public boolean isDeviceInteractive() { + return mKeyguardUpdateMonitor.isDeviceInteractive(); + } + + private void updateCanSkipBouncerState() { + mCanSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer(mCurrentUser); + } + + private void notifyKeyguardChanged() { + for (Callback callback : mCallbacks) { + callback.onKeyguardChanged(); + } + } +} \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 1a9756f78e364..a7fab41dd2878 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -159,7 +159,7 @@ public class NetworkControllerImpl extends BroadcastReceiver mConfig = config; mReceiverHandler = new Handler(bgLooper); mCallbackHandler = callbackHandler; - mDataSaverController = new DataSaverController(context); + mDataSaverController = new DataSaverControllerImpl(context); mSubscriptionManager = subManager; mSubDefaults = defaultsHandler; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java index 28935bff9ec54..e5b0c036b3266 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java @@ -1,84 +1,24 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * 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 * - * 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 + * 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 android.app.AlarmManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.UserHandle; import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; - -public class NextAlarmController extends BroadcastReceiver - implements CallbackController { - - private final ArrayList mChangeCallbacks = new ArrayList<>(); - - private AlarmManager mAlarmManager; - private AlarmManager.AlarmClockInfo mNextAlarm; - - public NextAlarmController(Context context) { - mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_USER_SWITCHED); - filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); - context.registerReceiverAsUser(this, UserHandle.ALL, filter, null, null); - updateNextAlarm(); - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("NextAlarmController state:"); - pw.print(" mNextAlarm="); pw.println(mNextAlarm); - } - - public void addCallback(NextAlarmChangeCallback cb) { - mChangeCallbacks.add(cb); - cb.onNextAlarmChanged(mNextAlarm); - } - - public void removeCallback(NextAlarmChangeCallback cb) { - mChangeCallbacks.remove(cb); - } - - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(Intent.ACTION_USER_SWITCHED) - || action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) { - updateNextAlarm(); - } - } - - private void updateNextAlarm() { - mNextAlarm = mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT); - fireNextAlarmChanged(); - } - - private void fireNextAlarmChanged() { - int n = mChangeCallbacks.size(); - for (int i = 0; i < n; i++) { - mChangeCallbacks.get(i).onNextAlarmChanged(mNextAlarm); - } - } +public interface NextAlarmController extends CallbackController { public interface NextAlarmChangeCallback { void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java new file mode 100644 index 0000000000000..dfdeae1fc4972 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2014 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 android.app.AlarmManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.UserHandle; + +import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; + +public class NextAlarmControllerImpl extends BroadcastReceiver + implements NextAlarmController { + + private final ArrayList mChangeCallbacks = new ArrayList<>(); + + private AlarmManager mAlarmManager; + private AlarmManager.AlarmClockInfo mNextAlarm; + + public NextAlarmControllerImpl(Context context) { + mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_USER_SWITCHED); + filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); + context.registerReceiverAsUser(this, UserHandle.ALL, filter, null, null); + updateNextAlarm(); + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("NextAlarmController state:"); + pw.print(" mNextAlarm="); pw.println(mNextAlarm); + } + + public void addCallback(NextAlarmChangeCallback cb) { + mChangeCallbacks.add(cb); + cb.onNextAlarmChanged(mNextAlarm); + } + + public void removeCallback(NextAlarmChangeCallback cb) { + mChangeCallbacks.remove(cb); + } + + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action.equals(Intent.ACTION_USER_SWITCHED) + || action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) { + updateNextAlarm(); + } + } + + private void updateNextAlarm() { + mNextAlarm = mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT); + fireNextAlarmChanged(); + } + + private void fireNextAlarmChanged() { + int n = mChangeCallbacks.size(); + for (int i = 0; i < n; i++) { + mChangeCallbacks.get(i).onNextAlarmChanged(mNextAlarm); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java index c09747b73f959..1e23a20c5ddbe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java @@ -1,233 +1,28 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * 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 * - * 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 + * 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 android.app.ActivityManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.pm.UserInfo; -import android.content.res.Resources; -import android.database.Cursor; -import android.graphics.Bitmap; import android.graphics.drawable.Drawable; -import android.os.AsyncTask; -import android.os.RemoteException; -import android.os.UserHandle; -import android.os.UserManager; -import android.provider.ContactsContract; -import android.util.Log; -import com.android.internal.util.UserIcons; -import com.android.settingslib.drawable.UserIconDrawable; -import com.android.systemui.R; import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener; -import java.util.ArrayList; +public interface UserInfoController extends CallbackController { -public class UserInfoController implements CallbackController { - - private static final String TAG = "UserInfoController"; - - private final Context mContext; - private final ArrayList mCallbacks = - new ArrayList(); - private AsyncTask mUserInfoTask; - - private String mUserName; - private Drawable mUserDrawable; - private String mUserAccount; - - public UserInfoController(Context context) { - mContext = context; - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_USER_SWITCHED); - mContext.registerReceiver(mReceiver, filter); - - IntentFilter profileFilter = new IntentFilter(); - profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED); - profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED); - mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter, - null, null); - } - - public void addCallback(OnUserInfoChangedListener callback) { - mCallbacks.add(callback); - callback.onUserInfoChanged(mUserName, mUserDrawable, mUserAccount); - } - - public void removeCallback(OnUserInfoChangedListener callback) { - mCallbacks.remove(callback); - } - - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (Intent.ACTION_USER_SWITCHED.equals(action)) { - reloadUserInfo(); - } - } - }; - - private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) || - Intent.ACTION_USER_INFO_CHANGED.equals(action)) { - try { - final int currentUser = ActivityManager.getService().getCurrentUser().id; - final int changedUser = - intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()); - if (changedUser == currentUser) { - reloadUserInfo(); - } - } catch (RemoteException e) { - Log.e(TAG, "Couldn't get current user id for profile change", e); - } - } - } - }; - - public void reloadUserInfo() { - if (mUserInfoTask != null) { - mUserInfoTask.cancel(false); - mUserInfoTask = null; - } - queryForUserInformation(); - } - - private void queryForUserInformation() { - Context currentUserContext; - UserInfo userInfo; - try { - userInfo = ActivityManager.getService().getCurrentUser(); - currentUserContext = mContext.createPackageContextAsUser("android", 0, - new UserHandle(userInfo.id)); - } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, "Couldn't create user context", e); - throw new RuntimeException(e); - } catch (RemoteException e) { - Log.e(TAG, "Couldn't get user info", e); - throw new RuntimeException(e); - } - final int userId = userInfo.id; - final boolean isGuest = userInfo.isGuest(); - final String userName = userInfo.name; - - final Resources res = mContext.getResources(); - final int avatarSize = Math.max( - res.getDimensionPixelSize(R.dimen.multi_user_avatar_expanded_size), - res.getDimensionPixelSize(R.dimen.multi_user_avatar_keyguard_size)); - - final Context context = currentUserContext; - mUserInfoTask = new AsyncTask() { - - @Override - protected UserInfoQueryResult doInBackground(Void... params) { - final UserManager um = UserManager.get(mContext); - - // Fall back to the UserManager nickname if we can't read the name from the local - // profile below. - String name = userName; - Drawable avatar = null; - Bitmap rawAvatar = um.getUserIcon(userId); - if (rawAvatar != null) { - avatar = new UserIconDrawable(avatarSize) - .setIcon(rawAvatar).setBadgeIfManagedUser(mContext, userId).bake(); - } else { - avatar = UserIcons.getDefaultUserIcon(isGuest? UserHandle.USER_NULL : userId, - /* light= */ true); - } - - // If it's a single-user device, get the profile name, since the nickname is not - // usually valid - if (um.getUsers().size() <= 1) { - // Try and read the display name from the local profile - final Cursor cursor = context.getContentResolver().query( - ContactsContract.Profile.CONTENT_URI, new String[] { - ContactsContract.CommonDataKinds.Phone._ID, - ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME - }, null, null, null); - if (cursor != null) { - try { - if (cursor.moveToFirst()) { - name = cursor.getString(cursor.getColumnIndex( - ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); - } - } finally { - cursor.close(); - } - } - } - String userAccount = um.getUserAccount(userId); - return new UserInfoQueryResult(name, avatar, userAccount); - } - - @Override - protected void onPostExecute(UserInfoQueryResult result) { - mUserName = result.getName(); - mUserDrawable = result.getAvatar(); - mUserAccount = result.getUserAccount(); - mUserInfoTask = null; - notifyChanged(); - } - }; - mUserInfoTask.execute(); - } - - private void notifyChanged() { - for (OnUserInfoChangedListener listener : mCallbacks) { - listener.onUserInfoChanged(mUserName, mUserDrawable, mUserAccount); - } - } - - public void onDensityOrFontScaleChanged() { - reloadUserInfo(); - } + void reloadUserInfo(); public interface OnUserInfoChangedListener { public void onUserInfoChanged(String name, Drawable picture, String userAccount); } - - private static class UserInfoQueryResult { - private String mName; - private Drawable mAvatar; - private String mUserAccount; - - public UserInfoQueryResult(String name, Drawable avatar, String userAccount) { - mName = name; - mAvatar = avatar; - mUserAccount = userAccount; - } - - public String getName() { - return mName; - } - - public Drawable getAvatar() { - return mAvatar; - } - - public String getUserAccount() { - return mUserAccount; - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java new file mode 100644 index 0000000000000..b1e4b03bb5b74 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2014 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 android.app.ActivityManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.UserInfo; +import android.content.res.Resources; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.ContactsContract; +import android.util.Log; + +import com.android.internal.util.UserIcons; +import com.android.settingslib.drawable.UserIconDrawable; +import com.android.systemui.R; +import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener; + +import java.util.ArrayList; + +public class UserInfoControllerImpl implements UserInfoController { + + private static final String TAG = "UserInfoController"; + + private final Context mContext; + private final ArrayList mCallbacks = + new ArrayList(); + private AsyncTask mUserInfoTask; + + private String mUserName; + private Drawable mUserDrawable; + private String mUserAccount; + + public UserInfoControllerImpl(Context context) { + mContext = context; + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_USER_SWITCHED); + mContext.registerReceiver(mReceiver, filter); + + IntentFilter profileFilter = new IntentFilter(); + profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED); + profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED); + mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter, + null, null); + } + + public void addCallback(OnUserInfoChangedListener callback) { + mCallbacks.add(callback); + callback.onUserInfoChanged(mUserName, mUserDrawable, mUserAccount); + } + + public void removeCallback(OnUserInfoChangedListener callback) { + mCallbacks.remove(callback); + } + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (Intent.ACTION_USER_SWITCHED.equals(action)) { + reloadUserInfo(); + } + } + }; + + private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) || + Intent.ACTION_USER_INFO_CHANGED.equals(action)) { + try { + final int currentUser = ActivityManager.getService().getCurrentUser().id; + final int changedUser = + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()); + if (changedUser == currentUser) { + reloadUserInfo(); + } + } catch (RemoteException e) { + Log.e(TAG, "Couldn't get current user id for profile change", e); + } + } + } + }; + + public void reloadUserInfo() { + if (mUserInfoTask != null) { + mUserInfoTask.cancel(false); + mUserInfoTask = null; + } + queryForUserInformation(); + } + + private void queryForUserInformation() { + Context currentUserContext; + UserInfo userInfo; + try { + userInfo = ActivityManager.getService().getCurrentUser(); + currentUserContext = mContext.createPackageContextAsUser("android", 0, + new UserHandle(userInfo.id)); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Couldn't create user context", e); + throw new RuntimeException(e); + } catch (RemoteException e) { + Log.e(TAG, "Couldn't get user info", e); + throw new RuntimeException(e); + } + final int userId = userInfo.id; + final boolean isGuest = userInfo.isGuest(); + final String userName = userInfo.name; + + final Resources res = mContext.getResources(); + final int avatarSize = Math.max( + res.getDimensionPixelSize(R.dimen.multi_user_avatar_expanded_size), + res.getDimensionPixelSize(R.dimen.multi_user_avatar_keyguard_size)); + + final Context context = currentUserContext; + mUserInfoTask = new AsyncTask() { + + @Override + protected UserInfoQueryResult doInBackground(Void... params) { + final UserManager um = UserManager.get(mContext); + + // Fall back to the UserManager nickname if we can't read the name from the local + // profile below. + String name = userName; + Drawable avatar = null; + Bitmap rawAvatar = um.getUserIcon(userId); + if (rawAvatar != null) { + avatar = new UserIconDrawable(avatarSize) + .setIcon(rawAvatar).setBadgeIfManagedUser(mContext, userId).bake(); + } else { + avatar = UserIcons.getDefaultUserIcon(isGuest? UserHandle.USER_NULL : userId, + /* light= */ true); + } + + // If it's a single-user device, get the profile name, since the nickname is not + // usually valid + if (um.getUsers().size() <= 1) { + // Try and read the display name from the local profile + final Cursor cursor = context.getContentResolver().query( + ContactsContract.Profile.CONTENT_URI, new String[] { + ContactsContract.CommonDataKinds.Phone._ID, + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + }, null, null, null); + if (cursor != null) { + try { + if (cursor.moveToFirst()) { + name = cursor.getString(cursor.getColumnIndex( + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); + } + } finally { + cursor.close(); + } + } + } + String userAccount = um.getUserAccount(userId); + return new UserInfoQueryResult(name, avatar, userAccount); + } + + @Override + protected void onPostExecute(UserInfoQueryResult result) { + mUserName = result.getName(); + mUserDrawable = result.getAvatar(); + mUserAccount = result.getUserAccount(); + mUserInfoTask = null; + notifyChanged(); + } + }; + mUserInfoTask.execute(); + } + + private void notifyChanged() { + for (OnUserInfoChangedListener listener : mCallbacks) { + listener.onUserInfoChanged(mUserName, mUserDrawable, mUserAccount); + } + } + + public void onDensityOrFontScaleChanged() { + reloadUserInfo(); + } + + private static class UserInfoQueryResult { + private String mName; + private Drawable mAvatar; + private String mUserAccount; + + public UserInfoQueryResult(String name, Drawable avatar, String userAccount) { + mName = name; + mAvatar = avatar; + mUserAccount = userAccount; + } + + public String getName() { + return mName; + } + + public Drawable getAvatar() { + return mAvatar; + } + + public String getUserAccount() { + return mUserAccount; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java index ebc962d14e7b9..565ac08f92ee4 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java @@ -92,6 +92,10 @@ public class TunerService extends SystemUI { mUserTracker.startTracking(); } + public void destroy() { + mUserTracker.stopTracking(); + } + private void upgradeTuner(int oldVersion, int newVersion) { if (oldVersion < 1) { String blacklistStr = getValue(StatusBarIconController.ICON_BLACKLIST); diff --git a/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/FragmentTestCase.java index f87336c7d1515..447edace3028d 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.LayoutInflater; 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 @@ public abstract class FragmentTestCase extends LeakCheckedTest { private class HostCallbacks extends FragmentHostCallback { 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 d64669d66049d..0000000000000 --- 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 mTrackers = new HashMap<>(); - private final Map 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 getLeakChecker(Class 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 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 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() { - @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() { - @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 addListening(final String tag, Class cls) { - T mock = mock(cls); - doAnswer(new Answer() { - @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() { - @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 5dac8e54aa215..008580ad6944e 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.Looper; 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 @@ import org.junit.Before; /** * 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 @@ public class SysuiTestCase { } } + // 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 6ceaeada2643d..1973b540494c1 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.SecurityController; 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 @@ public class QSFragmentTest extends FragmentTestCase { 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 @@ public class QSFragmentTest extends FragmentTestCase { 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 517982361424c..bf73416ffcff0 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 @@ public class TestableContext extends ContextWrapper { 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 @@ public class TestableContext extends ContextWrapper { // 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 0000000000000..0238bf7cb0045 --- /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 implements CallbackController { + + 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 0000000000000..fa07d337cd3d9 --- /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 + 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 0000000000000..6074a011fd206 --- /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 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 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 0000000000000..08211f857cb8a --- /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 implements CastController { + public FakeCastController(LeakCheckedTest test) { + super(test, "cast"); + } + + @Override + public void setDiscovering(boolean request) { + + } + + @Override + public void setCurrentUserId(int currentUserId) { + + } + + @Override + public Set 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 0000000000000..857a78510c1ed --- /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 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 0000000000000..630abd75af97f --- /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 + 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 0000000000000..781960d82e590 --- /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 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 0000000000000..39bbf2dfc42d7 --- /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 mCallbackController; + + public FakeKeyguardMonitor(LeakCheckedTest test) { + mCallbackController = new BaseLeakChecker(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 0000000000000..eab436cd87506 --- /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 + 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 0000000000000..0ec0d778a472e --- /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 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 0000000000000..fcfe9aa8f5d2f --- /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 + implements NetworkController { + + private final FakeDataSaverController mDataSaverController; + private final BaseLeakChecker mEmergencyChecker; + + public FakeNetworkController(LeakCheckedTest test) { + super(test, "network"); + mDataSaverController = new FakeDataSaverController(test); + mEmergencyChecker = new BaseLeakChecker(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 0000000000000..707fc4b4880dd --- /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 + 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 0000000000000..00e2404e931fc --- /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 + 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 0000000000000..331df58a05640 --- /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 + 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 0000000000000..578b31089d752 --- /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 + 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 0000000000000..13ea385d6c6ee --- /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 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 0000000000000..728ed606cffb6 --- /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 mTrackers = new HashMap<>(); + private final Map mLeakCheckers = new ArrayMap<>(); + + @Rule + public TestWatcher successWatcher = new TestWatcher() { + @Override + protected void succeeded(Description description) { + verify(); + } + }; + + public T getLeakChecker(Class 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 addListening(T mock, Class cls, String tag) { + doAnswer(new Answer() { + @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() { + @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 0000000000000..1d016fbe092b5 --- /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 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 0000000000000..26ffd10b83620 --- /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 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); + } +}