Break VolumeDialogControllerImpl' dependency on StatusBar
VolumeDialogControllerImpl had a reference to a lazy StatusBar. Because of how it was used, this could result in trying to stand up StatusBar (and all of its dependencies) on a non-main thread, which they did not appreciate. This removes the dependency on StatusBar, and throws in a healthy dash of dependency injection while we're at it. Fixes: 189203821 Test: atest SystemUITests && manual Change-Id: I41e00438b30928815e9355162af05f926f24dfce
This commit is contained in:
@@ -236,7 +236,7 @@ public class ScreenDecorations extends SystemUI implements Tunable {
|
||||
Log.i(TAG, "ScreenDecorations is disabled");
|
||||
return;
|
||||
}
|
||||
mHandler = mThreadFactory.builderHandlerOnNewThread("ScreenDecorations");
|
||||
mHandler = mThreadFactory.buildHandlerOnNewThread("ScreenDecorations");
|
||||
mExecutor = mThreadFactory.buildDelayableExecutorOnHandler(mHandler);
|
||||
mExecutor.execute(this::startOnScreenDecorationsThread);
|
||||
mDotViewController.setUiExecutor(mExecutor);
|
||||
|
||||
@@ -46,6 +46,7 @@ import android.hardware.display.DisplayManager;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.media.AudioManager;
|
||||
import android.media.IAudioService;
|
||||
import android.media.MediaRouter2Manager;
|
||||
import android.media.session.MediaSessionManager;
|
||||
import android.net.ConnectivityManager;
|
||||
@@ -77,6 +78,8 @@ import com.android.systemui.dagger.qualifiers.DisplayId;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.shared.system.PackageManagerWrapper;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Module;
|
||||
@@ -165,6 +168,13 @@ public class FrameworkServicesModule {
|
||||
return ActivityTaskManager.getService();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static IAudioService provideIAudioService() {
|
||||
return IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE));
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static IBatteryStats provideIBatteryStats() {
|
||||
@@ -360,6 +370,12 @@ public class FrameworkServicesModule {
|
||||
return context.getSystemService(Vibrator.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static Optional<Vibrator> provideOptionalVibrator(Context context) {
|
||||
return Optional.ofNullable(context.getSystemService(Vibrator.class));
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static ViewConfiguration provideViewConfiguration(Context context) {
|
||||
|
||||
@@ -23,7 +23,6 @@ import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settingslib.mobile.TelephonyIcons;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.statusbar.policy.NetworkController;
|
||||
@@ -63,6 +62,7 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba
|
||||
private final SecurityController mSecurityController;
|
||||
private final Handler mHandler = Handler.getMain();
|
||||
private final CarrierConfigTracker mCarrierConfigTracker;
|
||||
private final TunerService mTunerService;
|
||||
|
||||
private boolean mHideAirplane;
|
||||
private boolean mHideMobile;
|
||||
@@ -83,9 +83,16 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba
|
||||
|
||||
@Inject
|
||||
public StatusBarSignalPolicy(Context context, StatusBarIconController iconController,
|
||||
CarrierConfigTracker carrierConfigTracker) {
|
||||
CarrierConfigTracker carrierConfigTracker, NetworkController networkController,
|
||||
SecurityController securityController, TunerService tunerService) {
|
||||
mContext = context;
|
||||
|
||||
mIconController = iconController;
|
||||
mCarrierConfigTracker = carrierConfigTracker;
|
||||
mNetworkController = networkController;
|
||||
mSecurityController = securityController;
|
||||
mTunerService = tunerService;
|
||||
|
||||
mSlotAirplane = mContext.getString(com.android.internal.R.string.status_bar_airplane);
|
||||
mSlotMobile = mContext.getString(com.android.internal.R.string.status_bar_mobile);
|
||||
mSlotWifi = mContext.getString(com.android.internal.R.string.status_bar_wifi);
|
||||
@@ -96,18 +103,14 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba
|
||||
mContext.getString(com.android.internal.R.string.status_bar_call_strength);
|
||||
mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);
|
||||
|
||||
mIconController = iconController;
|
||||
mCarrierConfigTracker = carrierConfigTracker;
|
||||
mNetworkController = Dependency.get(NetworkController.class);
|
||||
mSecurityController = Dependency.get(SecurityController.class);
|
||||
|
||||
Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
|
||||
tunerService.addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
|
||||
mNetworkController.addCallback(this);
|
||||
mSecurityController.addCallback(this);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
Dependency.get(TunerService.class).removeTunable(this);
|
||||
mTunerService.removeTunable(this);
|
||||
mNetworkController.removeCallback(this);
|
||||
mSecurityController.removeCallback(this);
|
||||
}
|
||||
|
||||
@@ -29,13 +29,21 @@ import java.util.concurrent.Executor;
|
||||
* threads; there are no singletons here. Use responsibly.
|
||||
*/
|
||||
public interface ThreadFactory {
|
||||
/**
|
||||
* Returns a {@link Looper} running on a named thread.
|
||||
*
|
||||
* The thread is implicitly started and may be left running indefinitely, depending on the
|
||||
* implementation. Assume this is the case and use responsibly.
|
||||
*/
|
||||
Looper buildLooperOnNewThread(String threadName);
|
||||
|
||||
/**
|
||||
* Returns a {@link Handler} running on a named thread.
|
||||
*
|
||||
* The thread is implicitly started and may be left running indefinitely, depending on the
|
||||
* implementation. Assume this is the case and use responsibly.
|
||||
*/
|
||||
Handler builderHandlerOnNewThread(String threadName);
|
||||
Handler buildHandlerOnNewThread(String threadName);
|
||||
|
||||
/**
|
||||
* Return an {@link java.util.concurrent.Executor} running on a named thread.
|
||||
|
||||
@@ -29,10 +29,15 @@ class ThreadFactoryImpl implements ThreadFactory {
|
||||
ThreadFactoryImpl() {}
|
||||
|
||||
@Override
|
||||
public Handler builderHandlerOnNewThread(String threadName) {
|
||||
public Looper buildLooperOnNewThread(String threadName) {
|
||||
HandlerThread handlerThread = new HandlerThread(threadName);
|
||||
handlerThread.start();
|
||||
return new Handler(handlerThread.getLooper());
|
||||
return handlerThread.getLooper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Handler buildHandlerOnNewThread(String threadName) {
|
||||
return new Handler(buildLooperOnNewThread(threadName));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,11 +38,9 @@ import android.media.session.MediaController.PlaybackInfo;
|
||||
import android.media.session.MediaSession.Token;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
@@ -66,9 +64,9 @@ import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.keyguard.WakefulnessLifecycle;
|
||||
import com.android.systemui.plugins.VolumeDialogController;
|
||||
import com.android.systemui.qs.tiles.DndTile;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.util.RingerModeLiveData;
|
||||
import com.android.systemui.util.RingerModeTracker;
|
||||
import com.android.systemui.util.concurrency.ThreadFactory;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
@@ -80,8 +78,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.Lazy;
|
||||
|
||||
/**
|
||||
* Source of truth for all state / events related to the volume dialog. No presentation.
|
||||
*
|
||||
@@ -118,12 +114,13 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
|
||||
STREAMS.put(AudioSystem.STREAM_VOICE_CALL, R.string.stream_voice_call);
|
||||
}
|
||||
|
||||
private final HandlerThread mWorkerThread;
|
||||
private final W mWorker;
|
||||
private final Context mContext;
|
||||
private final Looper mWorkerLooper;
|
||||
private final PackageManager mPackageManager;
|
||||
private final WakefulnessLifecycle mWakefulnessLifecycle;
|
||||
private AudioManager mAudio;
|
||||
private IAudioService mAudioService;
|
||||
private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
|
||||
private final NotificationManager mNoMan;
|
||||
private final SettingObserver mObserver;
|
||||
private final Receiver mReceiver = new Receiver();
|
||||
@@ -132,13 +129,13 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
|
||||
protected C mCallbacks = new C();
|
||||
private final State mState = new State();
|
||||
protected final MediaSessionsCallbacks mMediaSessionsCallbacksW = new MediaSessionsCallbacks();
|
||||
private final Vibrator mVibrator;
|
||||
private final Optional<Vibrator> mVibrator;
|
||||
private final boolean mHasVibrator;
|
||||
private boolean mShowA11yStream;
|
||||
private boolean mShowVolumeDialog;
|
||||
private boolean mShowSafetyWarning;
|
||||
private long mLastToggledRingerOn;
|
||||
private final NotificationManager mNotificationManager;
|
||||
private boolean mDeviceInteractive;
|
||||
|
||||
private boolean mDestroyed;
|
||||
private VolumePolicy mVolumePolicy;
|
||||
@@ -149,26 +146,42 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
|
||||
protected final VC mVolumeController = new VC();
|
||||
protected final BroadcastDispatcher mBroadcastDispatcher;
|
||||
|
||||
@Inject
|
||||
public VolumeDialogControllerImpl(Context context, BroadcastDispatcher broadcastDispatcher,
|
||||
Optional<Lazy<StatusBar>> statusBarOptionalLazy, RingerModeTracker ringerModeTracker) {
|
||||
mContext = context.getApplicationContext();
|
||||
// TODO(b/150663459): remove this TV workaround once StatusBar is "unbound" on TVs
|
||||
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
|
||||
mStatusBarOptionalLazy = Optional.empty();
|
||||
} else {
|
||||
mStatusBarOptionalLazy = statusBarOptionalLazy;
|
||||
private final WakefulnessLifecycle.Observer mWakefullnessLifecycleObserver =
|
||||
new WakefulnessLifecycle.Observer() {
|
||||
@Override
|
||||
public void onStartedWakingUp() {
|
||||
mDeviceInteractive = true;
|
||||
}
|
||||
mNotificationManager = (NotificationManager) mContext.getSystemService(
|
||||
Context.NOTIFICATION_SERVICE);
|
||||
|
||||
@Override
|
||||
public void onFinishedGoingToSleep() {
|
||||
mDeviceInteractive = false;
|
||||
}
|
||||
};
|
||||
|
||||
@Inject
|
||||
public VolumeDialogControllerImpl(
|
||||
Context context,
|
||||
BroadcastDispatcher broadcastDispatcher,
|
||||
RingerModeTracker ringerModeTracker,
|
||||
ThreadFactory theadFactory,
|
||||
AudioManager audioManager,
|
||||
NotificationManager notificationManager,
|
||||
Optional<Vibrator> optionalVibrator,
|
||||
IAudioService iAudioService,
|
||||
AccessibilityManager accessibilityManager,
|
||||
PackageManager packageManager,
|
||||
WakefulnessLifecycle wakefulnessLifecycle) {
|
||||
mContext = context.getApplicationContext();
|
||||
mPackageManager = packageManager;
|
||||
mWakefulnessLifecycle = wakefulnessLifecycle;
|
||||
Events.writeEvent(Events.EVENT_COLLECTION_STARTED);
|
||||
mWorkerThread = new HandlerThread(VolumeDialogControllerImpl.class.getSimpleName());
|
||||
mWorkerThread.start();
|
||||
mWorker = new W(mWorkerThread.getLooper());
|
||||
mMediaSessions = createMediaSessions(mContext, mWorkerThread.getLooper(),
|
||||
mMediaSessionsCallbacksW);
|
||||
mAudio = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
mNoMan = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
mWorkerLooper = theadFactory.buildLooperOnNewThread(
|
||||
VolumeDialogControllerImpl.class.getSimpleName());
|
||||
mWorker = new W(mWorkerLooper);
|
||||
mMediaSessions = createMediaSessions(mContext, mWorkerLooper, mMediaSessionsCallbacksW);
|
||||
mAudio = audioManager;
|
||||
mNoMan = notificationManager;
|
||||
mObserver = new SettingObserver(mWorker);
|
||||
mRingerModeObservers = new RingerModeObservers(
|
||||
(RingerModeLiveData) ringerModeTracker.getRingerMode(),
|
||||
@@ -178,16 +191,17 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
|
||||
mBroadcastDispatcher = broadcastDispatcher;
|
||||
mObserver.init();
|
||||
mReceiver.init();
|
||||
mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
|
||||
mAudioService = IAudioService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.AUDIO_SERVICE));
|
||||
mVibrator = optionalVibrator;
|
||||
mHasVibrator = mVibrator.isPresent() && mVibrator.get().hasVibrator();
|
||||
mAudioService = iAudioService;
|
||||
|
||||
boolean accessibilityVolumeStreamActive = context.getSystemService(
|
||||
AccessibilityManager.class).isAccessibilityVolumeStreamActive();
|
||||
boolean accessibilityVolumeStreamActive = accessibilityManager
|
||||
.isAccessibilityVolumeStreamActive();
|
||||
mVolumeController.setA11yMode(accessibilityVolumeStreamActive ?
|
||||
VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
|
||||
VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
|
||||
|
||||
mWakefulnessLifecycle.addObserver(mWakefullnessLifecycleObserver);
|
||||
}
|
||||
|
||||
public AudioManager getAudioManager() {
|
||||
@@ -203,7 +217,6 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
|
||||
mAudio.setVolumeController(mVolumeController);
|
||||
} catch (SecurityException e) {
|
||||
Log.w(TAG, "Unable to set the volume controller", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,18 +262,6 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
|
||||
return new MediaSessions(context, looper, callbacks);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (D.BUG) Log.d(TAG, "destroy");
|
||||
if (mDestroyed) return;
|
||||
mDestroyed = true;
|
||||
Events.writeEvent(Events.EVENT_COLLECTION_STOPPED);
|
||||
mMediaSessions.destroy();
|
||||
mObserver.destroy();
|
||||
mReceiver.destroy();
|
||||
mRingerModeObservers.destroy();
|
||||
mWorkerThread.quitSafely();
|
||||
}
|
||||
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println(VolumeDialogControllerImpl.class.getSimpleName() + " state:");
|
||||
pw.print(" mDestroyed: "); pw.println(mDestroyed);
|
||||
@@ -383,9 +384,8 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
|
||||
}
|
||||
|
||||
public void vibrate(VibrationEffect effect) {
|
||||
if (mHasVibrator) {
|
||||
mVibrator.vibrate(effect, SONIFICIATION_VIBRATION_ATTRIBUTES);
|
||||
}
|
||||
mVibrator.ifPresent(
|
||||
vibrator -> vibrator.vibrate(effect, SONIFICIATION_VIBRATION_ATTRIBUTES));
|
||||
}
|
||||
|
||||
public boolean hasVibrator() {
|
||||
@@ -437,9 +437,8 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
|
||||
return;
|
||||
}
|
||||
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
mCallbacks.onCaptionComponentStateChanged(
|
||||
packageManager.getComponentEnabledSetting(componentName)
|
||||
mPackageManager.getComponentEnabledSetting(componentName)
|
||||
== PackageManager.COMPONENT_ENABLED_STATE_ENABLED, fromTooltip);
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG,
|
||||
@@ -466,17 +465,11 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
|
||||
}
|
||||
|
||||
private boolean shouldShowUI(int flags) {
|
||||
// if status bar isn't null, check if phone is in AOD, else check flags
|
||||
// since we could be using a different status bar
|
||||
return mStatusBarOptionalLazy.map(statusBarLazy -> {
|
||||
StatusBar statusBar = statusBarLazy.get();
|
||||
return statusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
|
||||
&& statusBar.getWakefulnessState()
|
||||
!= WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
|
||||
&& statusBar.isDeviceInteractive() && (flags & AudioManager.FLAG_SHOW_UI) != 0
|
||||
&& mShowVolumeDialog;
|
||||
}).orElse(
|
||||
mShowVolumeDialog && (flags & AudioManager.FLAG_SHOW_UI) != 0);
|
||||
int wakefulness = mWakefulnessLifecycle.getWakefulness();
|
||||
return wakefulness != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
|
||||
&& wakefulness != WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
|
||||
&& mDeviceInteractive && (flags & AudioManager.FLAG_SHOW_UI) != 0
|
||||
&& mShowVolumeDialog;
|
||||
}
|
||||
|
||||
boolean onVolumeChangedW(int stream, int flags) {
|
||||
@@ -600,15 +593,15 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
|
||||
private boolean updateEffectsSuppressorW(ComponentName effectsSuppressor) {
|
||||
if (Objects.equals(mState.effectsSuppressor, effectsSuppressor)) return false;
|
||||
mState.effectsSuppressor = effectsSuppressor;
|
||||
mState.effectsSuppressorName = getApplicationName(mContext, mState.effectsSuppressor);
|
||||
mState.effectsSuppressorName =
|
||||
getApplicationName(mPackageManager, mState.effectsSuppressor);
|
||||
Events.writeEvent(Events.EVENT_SUPPRESSOR_CHANGED, mState.effectsSuppressor,
|
||||
mState.effectsSuppressorName);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String getApplicationName(Context context, ComponentName component) {
|
||||
private static String getApplicationName(PackageManager pm, ComponentName component) {
|
||||
if (component == null) return null;
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
final String pkg = component.getPackageName();
|
||||
try {
|
||||
final ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
|
||||
@@ -630,8 +623,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
|
||||
}
|
||||
|
||||
private boolean updateZenConfig() {
|
||||
final NotificationManager.Policy policy =
|
||||
mNotificationManager.getConsolidatedNotificationPolicy();
|
||||
final NotificationManager.Policy policy = mNoMan.getConsolidatedNotificationPolicy();
|
||||
boolean disallowAlarms = (policy.priorityCategories & NotificationManager.Policy
|
||||
.PRIORITY_CATEGORY_ALARMS) == 0;
|
||||
boolean disallowMedia = (policy.priorityCategories & NotificationManager.Policy
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.concurrent.Executor;
|
||||
public class FakeThreadFactory implements ThreadFactory {
|
||||
private final FakeExecutor mFakeExecutor;
|
||||
private Handler mHandler;
|
||||
private Looper mLooper;
|
||||
|
||||
public FakeThreadFactory(FakeExecutor fakeExecutor) {
|
||||
mFakeExecutor = fakeExecutor;
|
||||
@@ -36,8 +37,17 @@ public class FakeThreadFactory implements ThreadFactory {
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
public void setLooper(Looper looper) {
|
||||
mLooper = looper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Handler builderHandlerOnNewThread(String threadName) {
|
||||
public Looper buildLooperOnNewThread(String threadName) {
|
||||
return mLooper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Handler buildHandlerOnNewThread(String threadName) {
|
||||
return mHandler;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,29 +23,37 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.media.AudioManager;
|
||||
import android.media.IAudioService;
|
||||
import android.media.session.MediaSession;
|
||||
import android.os.Handler;
|
||||
import android.os.Process;
|
||||
import android.os.Vibrator;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.keyguard.WakefulnessLifecycle;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.util.RingerModeLiveData;
|
||||
import com.android.systemui.util.RingerModeTracker;
|
||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||
import com.android.systemui.util.concurrency.FakeThreadFactory;
|
||||
import com.android.systemui.util.concurrency.ThreadFactory;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@@ -58,7 +66,6 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
|
||||
|
||||
TestableVolumeDialogControllerImpl mVolumeController;
|
||||
VolumeDialogControllerImpl.C mCallback;
|
||||
StatusBar mStatusBar;
|
||||
@Mock
|
||||
private BroadcastDispatcher mBroadcastDispatcher;
|
||||
@Mock
|
||||
@@ -67,6 +74,23 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
|
||||
private RingerModeLiveData mRingerModeLiveData;
|
||||
@Mock
|
||||
private RingerModeLiveData mRingerModeInternalLiveData;
|
||||
private final FakeThreadFactory mThreadFactory = new FakeThreadFactory(
|
||||
new FakeExecutor(new FakeSystemClock()));
|
||||
@Mock
|
||||
private AudioManager mAudioManager;
|
||||
@Mock
|
||||
private NotificationManager mNotificationManager;
|
||||
@Mock
|
||||
private Vibrator mVibrator;
|
||||
@Mock
|
||||
private IAudioService mIAudioService;
|
||||
@Mock
|
||||
private AccessibilityManager mAccessibilityManager;
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
private WakefulnessLifecycle mWakefullnessLifcycle;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
@@ -77,19 +101,15 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
|
||||
// Initial non-set value
|
||||
when(mRingerModeLiveData.getValue()).thenReturn(-1);
|
||||
when(mRingerModeInternalLiveData.getValue()).thenReturn(-1);
|
||||
|
||||
mCallback = mock(VolumeDialogControllerImpl.C.class);
|
||||
mStatusBar = mock(StatusBar.class);
|
||||
mVolumeController = new TestableVolumeDialogControllerImpl(mContext, mCallback, mStatusBar,
|
||||
mBroadcastDispatcher, mRingerModeTracker);
|
||||
mThreadFactory.setLooper(TestableLooper.get(this).getLooper());
|
||||
mVolumeController = new TestableVolumeDialogControllerImpl(mContext,
|
||||
mBroadcastDispatcher, mRingerModeTracker, mThreadFactory, mAudioManager,
|
||||
mNotificationManager, Optional.of(mVibrator), mIAudioService, mAccessibilityManager,
|
||||
mPackageManager, mWakefullnessLifcycle, mCallback);
|
||||
mVolumeController.setEnableDialogs(true, true);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mVolumeController.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisteredWithDispatcher() {
|
||||
verify(mBroadcastDispatcher).registerReceiverWithHandler(any(BroadcastReceiver.class),
|
||||
@@ -99,44 +119,35 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testVolumeChangeW_deviceNotInteractiveAOD() {
|
||||
when(mStatusBar.isDeviceInteractive()).thenReturn(false);
|
||||
when(mStatusBar.getWakefulnessState()).thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
|
||||
mVolumeController.setDeviceInteractive(false);
|
||||
when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
|
||||
WakefulnessLifecycle.WAKEFULNESS_AWAKE);
|
||||
mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
|
||||
verify(mCallback, never()).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeChangeW_deviceInteractive() {
|
||||
when(mStatusBar.isDeviceInteractive()).thenReturn(true);
|
||||
when(mStatusBar.getWakefulnessState()).thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
|
||||
mVolumeController.setDeviceInteractive(true);
|
||||
when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
|
||||
WakefulnessLifecycle.WAKEFULNESS_AWAKE);
|
||||
mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
|
||||
verify(mCallback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeChangeW_deviceInteractive_StartedSleeping() {
|
||||
when(mStatusBar.isDeviceInteractive()).thenReturn(true);
|
||||
when(mStatusBar.getWakefulnessState()).thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
|
||||
mVolumeController.setDeviceInteractive(true);
|
||||
when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
|
||||
WakefulnessLifecycle.WAKEFULNESS_AWAKE);
|
||||
mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
|
||||
when(mStatusBar.isDeviceInteractive()).thenReturn(false);
|
||||
when(mStatusBar.getWakefulnessState()).thenReturn(
|
||||
mVolumeController.setDeviceInteractive(false);
|
||||
when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
|
||||
WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP);
|
||||
mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
|
||||
verify(mCallback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVolumeChangeW_nullStatusBar() {
|
||||
VolumeDialogControllerImpl.C callback = mock(VolumeDialogControllerImpl.C.class);
|
||||
TestableVolumeDialogControllerImpl
|
||||
nullStatusBarTestableDialog =
|
||||
new TestableVolumeDialogControllerImpl(
|
||||
mContext, callback, null, mBroadcastDispatcher, mRingerModeTracker);
|
||||
nullStatusBarTestableDialog.setEnableDialogs(true, true);
|
||||
nullStatusBarTestableDialog.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
|
||||
verify(callback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnRemoteVolumeChanged_newStream_noNullPointer() {
|
||||
MediaSession.Token token = new MediaSession.Token(Process.myUid(), null);
|
||||
@@ -155,22 +166,51 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
|
||||
verify(mRingerModeInternalLiveData).observeForever(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRingerModeOnDestroy_observersRemoved() {
|
||||
mVolumeController.destroy();
|
||||
|
||||
verify(mRingerModeLiveData).removeObserver(any());
|
||||
verify(mRingerModeInternalLiveData).removeObserver(any());
|
||||
}
|
||||
|
||||
static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
|
||||
TestableVolumeDialogControllerImpl(Context context, C callback, StatusBar s,
|
||||
BroadcastDispatcher broadcastDispatcher, RingerModeTracker ringerModeTracker) {
|
||||
super(
|
||||
context, broadcastDispatcher,
|
||||
s == null ? Optional.empty() : Optional.of(() -> s), ringerModeTracker);
|
||||
private final WakefulnessLifecycle.Observer mWakefullessLifecycleObserver;
|
||||
|
||||
TestableVolumeDialogControllerImpl(
|
||||
Context context,
|
||||
BroadcastDispatcher broadcastDispatcher,
|
||||
RingerModeTracker ringerModeTracker,
|
||||
ThreadFactory theadFactory,
|
||||
AudioManager audioManager,
|
||||
NotificationManager notificationManager,
|
||||
Optional<Vibrator> optionalVibrator,
|
||||
IAudioService iAudioService,
|
||||
AccessibilityManager accessibilityManager,
|
||||
PackageManager packageManager,
|
||||
WakefulnessLifecycle wakefulnessLifecycle,
|
||||
C callback) {
|
||||
super(context, broadcastDispatcher, ringerModeTracker, theadFactory, audioManager,
|
||||
notificationManager, optionalVibrator, iAudioService, accessibilityManager,
|
||||
packageManager, wakefulnessLifecycle);
|
||||
mCallbacks = callback;
|
||||
|
||||
ArgumentCaptor<WakefulnessLifecycle.Observer> observerCaptor =
|
||||
ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class);
|
||||
verify(wakefulnessLifecycle).addObserver(observerCaptor.capture());
|
||||
mWakefullessLifecycleObserver = observerCaptor.getValue();
|
||||
}
|
||||
|
||||
public void setDeviceInteractive(boolean interactive) {
|
||||
if (interactive) {
|
||||
mWakefullessLifecycleObserver.onStartedWakingUp();
|
||||
} else {
|
||||
mWakefullessLifecycleObserver.onFinishedGoingToSleep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
|
||||
// TestableVolumeDialogControllerImpl(Context context, C callback,
|
||||
// BroadcastDispatcher broadcastDispatcher, RingerModeTracker ringerModeTracker,
|
||||
// ThreadFactory threadFactory) {
|
||||
// super(
|
||||
// context, broadcastDispatcher,
|
||||
// s == null ? Optional.empty() : Optional.of(() -> s), ringerModeTracker);
|
||||
// mCallbacks = callback;
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user