Merge "Cleanup and refactoring of test utilities"
This commit is contained in:
committed by
Android (Google) Code Review
commit
6737226e40
@@ -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<Callback> {
|
||||
|
||||
public class ManagedProfileController implements CallbackController<Callback> {
|
||||
void setWorkModeEnabled(boolean enabled);
|
||||
|
||||
private final List<Callback> mCallbacks = new ArrayList<>();
|
||||
boolean hasActiveProfile();
|
||||
|
||||
private final Context mContext;
|
||||
private final UserManager mUserManager;
|
||||
private final LinkedList<UserInfo> mProfiles;
|
||||
private boolean mListening;
|
||||
private int mCurrentUser;
|
||||
|
||||
public ManagedProfileController(QSTileHost host) {
|
||||
mContext = host.getContext();
|
||||
mUserManager = UserManager.get(mContext);
|
||||
mProfiles = new LinkedList<UserInfo>();
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
@@ -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<Callback> mCallbacks = new ArrayList<>();
|
||||
|
||||
private final Context mContext;
|
||||
private final UserManager mUserManager;
|
||||
private final LinkedList<UserInfo> mProfiles;
|
||||
private boolean mListening;
|
||||
private int mCurrentUser;
|
||||
|
||||
public ManagedProfileControllerImpl(QSTileHost host) {
|
||||
mContext = host.getContext();
|
||||
mUserManager = UserManager.get(mContext);
|
||||
mProfiles = new LinkedList<UserInfo>();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Listener> {
|
||||
|
||||
public class DataSaverController implements CallbackController<Listener> {
|
||||
|
||||
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
private final ArrayList<Listener> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<Listener> 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 {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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<FlashlightListener> {
|
||||
|
||||
/**
|
||||
* Manages the flashlight.
|
||||
*/
|
||||
public class FlashlightController implements CallbackController<FlashlightListener> {
|
||||
|
||||
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<WeakReference<FlashlightListener>> 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 {
|
||||
|
||||
|
||||
@@ -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<WeakReference<FlashlightListener>> 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);
|
||||
}
|
||||
}
|
||||
@@ -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<Callback> {
|
||||
|
||||
public class KeyguardMonitor extends KeyguardUpdateMonitorCallback
|
||||
implements CallbackController<Callback> {
|
||||
|
||||
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Callback> mCallbacks = new ArrayList<Callback>();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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<NextAlarmChangeCallback> {
|
||||
|
||||
private final ArrayList<NextAlarmChangeCallback> 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<NextAlarmChangeCallback> {
|
||||
|
||||
public interface NextAlarmChangeCallback {
|
||||
void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm);
|
||||
|
||||
@@ -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<NextAlarmChangeCallback> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<OnUserInfoChangedListener> {
|
||||
|
||||
public class UserInfoController implements CallbackController<OnUserInfoChangedListener> {
|
||||
|
||||
private static final String TAG = "UserInfoController";
|
||||
|
||||
private final Context mContext;
|
||||
private final ArrayList<OnUserInfoChangedListener> mCallbacks =
|
||||
new ArrayList<OnUserInfoChangedListener>();
|
||||
private AsyncTask<Void, Void, UserInfoQueryResult> 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<Void, Void, UserInfoQueryResult>() {
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<OnUserInfoChangedListener> mCallbacks =
|
||||
new ArrayList<OnUserInfoChangedListener>();
|
||||
private AsyncTask<Void, Void, UserInfoQueryResult> 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<Void, Void, UserInfoQueryResult>() {
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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<FragmentTestCase> {
|
||||
public HostCallbacks() {
|
||||
super(getTrackedContext(), FragmentTestCase.this.mHandler, 0);
|
||||
super(mContext, FragmentTestCase.this.mHandler, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,287 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentCallbacks;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.systemui.statusbar.phone.ManagedProfileController;
|
||||
import com.android.systemui.statusbar.policy.BatteryController;
|
||||
import com.android.systemui.statusbar.policy.BluetoothController;
|
||||
import com.android.systemui.statusbar.policy.CastController;
|
||||
import com.android.systemui.statusbar.policy.DataSaverController;
|
||||
import com.android.systemui.statusbar.policy.FlashlightController;
|
||||
import com.android.systemui.statusbar.policy.HotspotController;
|
||||
import com.android.systemui.statusbar.policy.KeyguardMonitor;
|
||||
import com.android.systemui.statusbar.policy.LocationController;
|
||||
import com.android.systemui.statusbar.policy.NetworkController;
|
||||
import com.android.systemui.statusbar.policy.NextAlarmController;
|
||||
import com.android.systemui.statusbar.policy.RotationLockController;
|
||||
import com.android.systemui.statusbar.policy.SecurityController;
|
||||
import com.android.systemui.statusbar.policy.CallbackController;
|
||||
import com.android.systemui.statusbar.policy.UserInfoController;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TestWatcher;
|
||||
import org.junit.runner.Description;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base class for tests to check if receivers are left registered, services bound, or other
|
||||
* listeners listening.
|
||||
*/
|
||||
public class LeakCheckedTest extends SysuiTestCase {
|
||||
private static final String TAG = "LeakCheckedTest";
|
||||
|
||||
private final Map<String, Tracker> mTrackers = new HashMap<>();
|
||||
private final Map<Class, Object> mLeakCheckers = new ArrayMap<>();
|
||||
private TrackingContext mTrackedContext;
|
||||
|
||||
@Rule
|
||||
public TestWatcher successWatcher = new TestWatcher() {
|
||||
@Override
|
||||
protected void succeeded(Description description) {
|
||||
verify();
|
||||
}
|
||||
};
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mTrackedContext = new TrackingContext(mContext);
|
||||
addSupportedLeakCheckers();
|
||||
}
|
||||
|
||||
public <T> T getLeakChecker(Class<T> cls) {
|
||||
T obj = (T) mLeakCheckers.get(cls);
|
||||
if (obj == null) {
|
||||
Assert.fail(cls.getName() + " is not supported by LeakCheckedTest yet");
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public Context getTrackedContext() {
|
||||
return mTrackedContext;
|
||||
}
|
||||
|
||||
private Tracker getTracker(String tag) {
|
||||
Tracker t = mTrackers.get(tag);
|
||||
if (t == null) {
|
||||
t = new Tracker();
|
||||
mTrackers.put(tag, t);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public void verify() {
|
||||
mTrackers.values().forEach(Tracker::verify);
|
||||
}
|
||||
|
||||
public static class Tracker {
|
||||
private Map<Object, LeakInfo> mObjects = new ArrayMap<>();
|
||||
|
||||
LeakInfo getLeakInfo(Object object) {
|
||||
LeakInfo leakInfo = mObjects.get(object);
|
||||
if (leakInfo == null) {
|
||||
leakInfo = new LeakInfo();
|
||||
mObjects.put(object, leakInfo);
|
||||
}
|
||||
return leakInfo;
|
||||
}
|
||||
|
||||
private void verify() {
|
||||
mObjects.values().forEach(LeakInfo::verify);
|
||||
}
|
||||
}
|
||||
|
||||
public static class LeakInfo {
|
||||
private List<Throwable> mThrowables = new ArrayList<>();
|
||||
|
||||
private LeakInfo() {
|
||||
}
|
||||
|
||||
private void addAllocation(Throwable t) {
|
||||
// TODO: Drop off the first element in the stack trace here to have a cleaner stack.
|
||||
mThrowables.add(t);
|
||||
}
|
||||
|
||||
private void clearAllocations() {
|
||||
mThrowables.clear();
|
||||
}
|
||||
|
||||
public void verify() {
|
||||
if (mThrowables.size() == 0) return;
|
||||
Log.e(TAG, "Listener or binding not properly released");
|
||||
for (Throwable t : mThrowables) {
|
||||
Log.e(TAG, "Allocation found", t);
|
||||
}
|
||||
StringWriter writer = new StringWriter();
|
||||
mThrowables.get(0).printStackTrace(new PrintWriter(writer));
|
||||
Assert.fail("Listener or binding not properly released\n"
|
||||
+ writer.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void addSupportedLeakCheckers() {
|
||||
addListening("bluetooth", BluetoothController.class);
|
||||
addListening("location", LocationController.class);
|
||||
addListening("rotation", RotationLockController.class);
|
||||
addListening("zen", ZenModeController.class);
|
||||
addListening("cast", CastController.class);
|
||||
addListening("hotspot", HotspotController.class);
|
||||
addListening("flashlight", FlashlightController.class);
|
||||
addListening("user", UserInfoController.class);
|
||||
addListening("keyguard", KeyguardMonitor.class);
|
||||
addListening("battery", BatteryController.class);
|
||||
addListening("security", SecurityController.class);
|
||||
addListening("profile", ManagedProfileController.class);
|
||||
addListening("alarm", NextAlarmController.class);
|
||||
NetworkController network = addListening("network", NetworkController.class);
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
getTracker("emergency").getLeakInfo(invocation.getArguments()[0])
|
||||
.addAllocation(new Throwable());
|
||||
return null;
|
||||
}
|
||||
}).when(network).addEmergencyListener(any());
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
getTracker("emergency").getLeakInfo(invocation.getArguments()[0]).clearAllocations();
|
||||
return null;
|
||||
}
|
||||
}).when(network).removeEmergencyListener(any());
|
||||
DataSaverController datasaver = addListening("datasaver", DataSaverController.class);
|
||||
when(network.getDataSaverController()).thenReturn(datasaver);
|
||||
}
|
||||
|
||||
private <T extends CallbackController> T addListening(final String tag, Class<T> cls) {
|
||||
T mock = mock(cls);
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
getTracker(tag).getLeakInfo(invocation.getArguments()[0])
|
||||
.addAllocation(new Throwable());
|
||||
return null;
|
||||
}
|
||||
}).when(mock).addCallback(any());
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
getTracker(tag).getLeakInfo(invocation.getArguments()[0]).clearAllocations();
|
||||
return null;
|
||||
}
|
||||
}).when(mock).removeCallback(any());
|
||||
mLeakCheckers.put(cls, mock);
|
||||
return mock;
|
||||
}
|
||||
|
||||
class TrackingContext extends ContextWrapper {
|
||||
public TrackingContext(Context base) {
|
||||
super(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
|
||||
getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable());
|
||||
return super.registerReceiver(receiver, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
|
||||
String broadcastPermission, Handler scheduler) {
|
||||
getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable());
|
||||
return super.registerReceiver(receiver, filter, broadcastPermission, scheduler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
|
||||
IntentFilter filter, String broadcastPermission, Handler scheduler) {
|
||||
getTracker("receiver").getLeakInfo(receiver).addAllocation(new Throwable());
|
||||
return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
|
||||
scheduler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterReceiver(BroadcastReceiver receiver) {
|
||||
getTracker("receiver").getLeakInfo(receiver).clearAllocations();
|
||||
super.unregisterReceiver(receiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
|
||||
getTracker("service").getLeakInfo(conn).addAllocation(new Throwable());
|
||||
return super.bindService(service, conn, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
|
||||
Handler handler, UserHandle user) {
|
||||
getTracker("service").getLeakInfo(conn).addAllocation(new Throwable());
|
||||
return super.bindServiceAsUser(service, conn, flags, handler, user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
|
||||
UserHandle user) {
|
||||
getTracker("service").getLeakInfo(conn).addAllocation(new Throwable());
|
||||
return super.bindServiceAsUser(service, conn, flags, user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbindService(ServiceConnection conn) {
|
||||
getTracker("service").getLeakInfo(conn).clearAllocations();
|
||||
super.unbindService(conn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerComponentCallbacks(ComponentCallbacks callback) {
|
||||
getTracker("component").getLeakInfo(callback).addAllocation(new Throwable());
|
||||
super.registerComponentCallbacks(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterComponentCallbacks(ComponentCallbacks callback) {
|
||||
getTracker("component").getLeakInfo(callback).clearAllocations();
|
||||
super.unregisterComponentCallbacks(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import com.android.systemui.statusbar.policy.CallbackController;
|
||||
|
||||
public class BaseLeakChecker<T> implements CallbackController<T> {
|
||||
|
||||
private final Tracker mTracker;
|
||||
|
||||
public BaseLeakChecker(LeakCheckedTest test, String tag) {
|
||||
mTracker = test.getTracker(tag);
|
||||
}
|
||||
|
||||
protected final Tracker getTracker() {
|
||||
return mTracker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallback(T listener) {
|
||||
mTracker.getLeakInfo(listener).addAllocation(new Throwable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCallback(T listener) {
|
||||
mTracker.getLeakInfo(listener).clearAllocations();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.systemui.statusbar.policy.BatteryController;
|
||||
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
public class FakeBatteryController extends BaseLeakChecker<BatteryStateChangeCallback>
|
||||
implements BatteryController {
|
||||
public FakeBatteryController(LeakCheckedTest test) {
|
||||
super(test, "battery");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchDemoCommand(String command, Bundle args) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPowerSaveMode(boolean powerSave) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPowerSave() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.systemui.statusbar.policy.BluetoothController;
|
||||
import com.android.systemui.statusbar.policy.BluetoothController.Callback;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class FakeBluetoothController extends BaseLeakChecker<Callback> implements
|
||||
BluetoothController {
|
||||
|
||||
public FakeBluetoothController(LeakCheckedTest test) {
|
||||
super(test, "bluetooth");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBluetoothSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBluetoothEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBluetoothState() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBluetoothConnected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBluetoothConnecting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLastDeviceName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBluetoothEnabled(boolean enabled) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<CachedBluetoothDevice> getDevices() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(CachedBluetoothDevice device) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(CachedBluetoothDevice device) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canConfigBluetooth() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import com.android.systemui.statusbar.policy.CastController;
|
||||
import com.android.systemui.statusbar.policy.CastController.Callback;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class FakeCastController extends BaseLeakChecker<Callback> implements CastController {
|
||||
public FakeCastController(LeakCheckedTest test) {
|
||||
super(test, "cast");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDiscovering(boolean request) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentUserId(int currentUserId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CastDevice> getCastDevices() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startCasting(CastDevice device) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopCasting(CastDevice device) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import com.android.systemui.statusbar.policy.DataSaverController;
|
||||
import com.android.systemui.statusbar.policy.DataSaverController.Listener;
|
||||
|
||||
public class FakeDataSaverController extends BaseLeakChecker<Listener> implements DataSaverController {
|
||||
|
||||
public FakeDataSaverController(LeakCheckedTest test) {
|
||||
super(test, "datasaver");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataSaverEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataSaverEnabled(boolean enabled) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import com.android.systemui.statusbar.policy.FlashlightController;
|
||||
import com.android.systemui.statusbar.policy.FlashlightController.FlashlightListener;
|
||||
|
||||
public class FakeFlashlightController extends BaseLeakChecker<FlashlightListener>
|
||||
implements FlashlightController {
|
||||
public FakeFlashlightController(LeakCheckedTest test) {
|
||||
super(test, "flashlight");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFlashlight() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlashlight(boolean newState) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import com.android.systemui.statusbar.policy.HotspotController;
|
||||
import com.android.systemui.statusbar.policy.HotspotController.Callback;
|
||||
|
||||
public class FakeHotspotController extends BaseLeakChecker<Callback> implements HotspotController {
|
||||
|
||||
public FakeHotspotController(LeakCheckedTest test) {
|
||||
super(test, "hotspot");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHotspotEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHotspotEnabled(boolean enabled) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHotspotSupported() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import com.android.systemui.statusbar.policy.KeyguardMonitor;
|
||||
|
||||
public class FakeKeyguardMonitor implements KeyguardMonitor {
|
||||
|
||||
private final BaseLeakChecker<Callback> mCallbackController;
|
||||
|
||||
public FakeKeyguardMonitor(LeakCheckedTest test) {
|
||||
mCallbackController = new BaseLeakChecker<Callback>(test, "keyguard");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallback(Callback callback) {
|
||||
mCallbackController.addCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCallback(Callback callback) {
|
||||
mCallbackController.removeCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowing() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSkipBouncer() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import com.android.systemui.statusbar.policy.LocationController;
|
||||
import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback;
|
||||
|
||||
public class FakeLocationController extends BaseLeakChecker<LocationSettingsChangeCallback>
|
||||
implements LocationController {
|
||||
public FakeLocationController(LeakCheckedTest test) {
|
||||
super(test, "location");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocationEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setLocationEnabled(boolean enabled) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import com.android.systemui.statusbar.phone.ManagedProfileController;
|
||||
import com.android.systemui.statusbar.phone.ManagedProfileController.Callback;
|
||||
|
||||
public class FakeManagedProfileController extends BaseLeakChecker<Callback> implements
|
||||
ManagedProfileController {
|
||||
public FakeManagedProfileController(LeakCheckedTest test) {
|
||||
super(test, "profile");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWorkModeEnabled(boolean enabled) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActiveProfile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWorkModeEnabled() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import com.android.settingslib.net.DataUsageController;
|
||||
import com.android.systemui.statusbar.policy.DataSaverController;
|
||||
import com.android.systemui.statusbar.policy.NetworkController;
|
||||
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
|
||||
|
||||
public class FakeNetworkController extends BaseLeakChecker<SignalCallback>
|
||||
implements NetworkController {
|
||||
|
||||
private final FakeDataSaverController mDataSaverController;
|
||||
private final BaseLeakChecker<EmergencyListener> mEmergencyChecker;
|
||||
|
||||
public FakeNetworkController(LeakCheckedTest test) {
|
||||
super(test, "network");
|
||||
mDataSaverController = new FakeDataSaverController(test);
|
||||
mEmergencyChecker = new BaseLeakChecker<EmergencyListener>(test, "emergency");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEmergencyListener(EmergencyListener listener) {
|
||||
mEmergencyChecker.addCallback(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEmergencyListener(EmergencyListener listener) {
|
||||
mEmergencyChecker.removeCallback(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSaverController getDataSaverController() {
|
||||
return mDataSaverController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMobileDataFeature() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWifiEnabled(boolean enabled) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserSwitched(int newUserId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessPointController getAccessPointController() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataUsageController getMobileDataController() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasVoiceCallingFeature() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import com.android.systemui.statusbar.policy.NextAlarmController;
|
||||
import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
|
||||
|
||||
public class FakeNextAlarmController extends BaseLeakChecker<NextAlarmChangeCallback>
|
||||
implements NextAlarmController {
|
||||
|
||||
public FakeNextAlarmController(LeakCheckedTest test) {
|
||||
super(test, "alarm");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import com.android.systemui.statusbar.policy.RotationLockController;
|
||||
import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
|
||||
|
||||
public class FakeRotationLockController extends BaseLeakChecker<RotationLockControllerCallback>
|
||||
implements RotationLockController {
|
||||
public FakeRotationLockController(LeakCheckedTest test) {
|
||||
super(test, "rotation");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListening(boolean listening) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRotationLockOrientation() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRotationLockAffordanceVisible() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRotationLocked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRotationLocked(boolean locked) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import com.android.systemui.statusbar.policy.SecurityController;
|
||||
import com.android.systemui.statusbar.policy.SecurityController.SecurityControllerCallback;
|
||||
|
||||
public class FakeSecurityController extends BaseLeakChecker<SecurityControllerCallback>
|
||||
implements SecurityController {
|
||||
public FakeSecurityController(LeakCheckedTest test) {
|
||||
super(test, "security");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeviceManaged() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasProfileOwner() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceOwnerName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProfileOwnerName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getDeviceOwnerOrganizationName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVpnEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVpnRestricted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVpnBranded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrimaryVpnName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProfileVpnName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserSwitched(int newUserId) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import com.android.systemui.statusbar.policy.UserInfoController;
|
||||
import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
|
||||
|
||||
public class FakeUserInfoController extends BaseLeakChecker<OnUserInfoChangedListener>
|
||||
implements UserInfoController {
|
||||
public FakeUserInfoController(LeakCheckedTest test) {
|
||||
super(test, "user_info");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadUserInfo() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.net.Uri;
|
||||
import android.service.notification.ZenModeConfig;
|
||||
import android.service.notification.ZenModeConfig.ZenRule;
|
||||
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController.Callback;
|
||||
|
||||
public class FakeZenModeController extends BaseLeakChecker<Callback> implements ZenModeController {
|
||||
public FakeZenModeController(LeakCheckedTest test) {
|
||||
super(test, "zen");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setZen(int zen, Uri conditionId, String reason) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZen() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZenRule getManualRule() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZenModeConfig getConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNextAlarm() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserId(int userId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isZenAvailable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentName getEffectsSuppressor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCountdownConditionSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentUser() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVolumeRestricted() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.statusbar.phone.ManagedProfileController;
|
||||
import com.android.systemui.statusbar.policy.BatteryController;
|
||||
import com.android.systemui.statusbar.policy.BluetoothController;
|
||||
import com.android.systemui.statusbar.policy.CallbackController;
|
||||
import com.android.systemui.statusbar.policy.CastController;
|
||||
import com.android.systemui.statusbar.policy.FlashlightController;
|
||||
import com.android.systemui.statusbar.policy.HotspotController;
|
||||
import com.android.systemui.statusbar.policy.KeyguardMonitor;
|
||||
import com.android.systemui.statusbar.policy.LocationController;
|
||||
import com.android.systemui.statusbar.policy.NetworkController;
|
||||
import com.android.systemui.statusbar.policy.NextAlarmController;
|
||||
import com.android.systemui.statusbar.policy.RotationLockController;
|
||||
import com.android.systemui.statusbar.policy.SecurityController;
|
||||
import com.android.systemui.statusbar.policy.UserInfoController;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TestWatcher;
|
||||
import org.junit.runner.Description;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base class for tests to check if receivers are left registered, services bound, or other
|
||||
* listeners listening.
|
||||
*/
|
||||
public abstract class LeakCheckedTest extends SysuiTestCase {
|
||||
private static final String TAG = "LeakCheckedTest";
|
||||
|
||||
private final Map<String, Tracker> mTrackers = new HashMap<>();
|
||||
private final Map<Class, Object> mLeakCheckers = new ArrayMap<>();
|
||||
|
||||
@Rule
|
||||
public TestWatcher successWatcher = new TestWatcher() {
|
||||
@Override
|
||||
protected void succeeded(Description description) {
|
||||
verify();
|
||||
}
|
||||
};
|
||||
|
||||
public <T> T getLeakChecker(Class<T> cls) {
|
||||
Object obj = mLeakCheckers.get(cls);
|
||||
if (obj == null) {
|
||||
// Lazy create checkers so we only have the ones we need.
|
||||
if (cls == BluetoothController.class) {
|
||||
obj = new FakeBluetoothController(this);
|
||||
} else if (cls == LocationController.class) {
|
||||
obj = new FakeLocationController(this);
|
||||
} else if (cls == RotationLockController.class) {
|
||||
obj = new FakeRotationLockController(this);
|
||||
} else if (cls == ZenModeController.class) {
|
||||
obj = new FakeZenModeController(this);
|
||||
} else if (cls == CastController.class) {
|
||||
obj = new FakeCastController(this);
|
||||
} else if (cls == HotspotController.class) {
|
||||
obj = new FakeHotspotController(this);
|
||||
} else if (cls == FlashlightController.class) {
|
||||
obj = new FakeFlashlightController(this);
|
||||
} else if (cls == UserInfoController.class) {
|
||||
obj = new FakeUserInfoController(this);
|
||||
} else if (cls == KeyguardMonitor.class) {
|
||||
obj = new FakeKeyguardMonitor(this);
|
||||
} else if (cls == BatteryController.class) {
|
||||
obj = new FakeBatteryController(this);
|
||||
} else if (cls == SecurityController.class) {
|
||||
obj = new FakeSecurityController(this);
|
||||
} else if (cls == ManagedProfileController.class) {
|
||||
obj = new FakeManagedProfileController(this);
|
||||
} else if (cls == NextAlarmController.class) {
|
||||
obj = new FakeNextAlarmController(this);
|
||||
} else if (cls == NetworkController.class) {
|
||||
obj = new FakeNetworkController(this);
|
||||
} else {
|
||||
Assert.fail(cls.getName() + " is not supported by LeakCheckedTest yet");
|
||||
}
|
||||
mLeakCheckers.put(cls, obj);
|
||||
}
|
||||
return (T) obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracker getTracker(String tag) {
|
||||
Tracker t = mTrackers.get(tag);
|
||||
if (t == null) {
|
||||
t = new Tracker();
|
||||
mTrackers.put(tag, t);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public void verify() {
|
||||
mTrackers.values().forEach(Tracker::verify);
|
||||
}
|
||||
|
||||
public <T extends CallbackController> T addListening(T mock, Class<T> cls, String tag) {
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
getTracker(tag).getLeakInfo(invocation.getArguments()[0])
|
||||
.addAllocation(new Throwable());
|
||||
return null;
|
||||
}
|
||||
}).when(mock).addCallback(any());
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
getTracker(tag).getLeakInfo(invocation.getArguments()[0]).clearAllocations();
|
||||
return null;
|
||||
}
|
||||
}).when(mock).removeCallback(any());
|
||||
mLeakCheckers.put(cls, mock);
|
||||
return mock;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LeakInfo {
|
||||
private static final String TAG = "LeakInfo";
|
||||
private List<Throwable> mThrowables = new ArrayList<>();
|
||||
|
||||
LeakInfo() {
|
||||
}
|
||||
|
||||
public void addAllocation(Throwable t) {
|
||||
// TODO: Drop off the first element in the stack trace here to have a cleaner stack.
|
||||
mThrowables.add(t);
|
||||
}
|
||||
|
||||
public void clearAllocations() {
|
||||
mThrowables.clear();
|
||||
}
|
||||
|
||||
void verify() {
|
||||
if (mThrowables.size() == 0) return;
|
||||
Log.e(TAG, "Listener or binding not properly released");
|
||||
for (Throwable t : mThrowables) {
|
||||
Log.e(TAG, "Allocation found", t);
|
||||
}
|
||||
StringWriter writer = new StringWriter();
|
||||
mThrowables.get(0).printStackTrace(new PrintWriter(writer));
|
||||
Assert.fail("Listener or binding not properly released\n"
|
||||
+ writer.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.utils.leaks;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.android.systemui.utils.leaks.LeakInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class Tracker {
|
||||
private Map<Object, LeakInfo> mObjects = new ArrayMap<>();
|
||||
|
||||
public LeakInfo getLeakInfo(Object object) {
|
||||
LeakInfo leakInfo = mObjects.get(object);
|
||||
if (leakInfo == null) {
|
||||
leakInfo = new LeakInfo();
|
||||
mObjects.put(object, leakInfo);
|
||||
}
|
||||
return leakInfo;
|
||||
}
|
||||
|
||||
void verify() {
|
||||
mObjects.values().forEach(LeakInfo::verify);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user