Merge "Bouncer shouldn't be translated when occluded" into pi-dev
diff --git a/api/test-current.txt b/api/test-current.txt
index f1c6120..f0017b9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -621,6 +621,19 @@
method public static final int getThreadScheduler(int) throws java.lang.IllegalArgumentException;
}
+ public final class RemoteCallback implements android.os.Parcelable {
+ ctor public RemoteCallback(android.os.RemoteCallback.OnResultListener);
+ ctor public RemoteCallback(android.os.RemoteCallback.OnResultListener, android.os.Handler);
+ method public int describeContents();
+ method public void sendResult(android.os.Bundle);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.os.RemoteCallback> CREATOR;
+ }
+
+ public static abstract interface RemoteCallback.OnResultListener {
+ method public abstract void onResult(android.os.Bundle);
+ }
+
public final class StrictMode {
method public static void setViolationLogger(android.os.StrictMode.ViolationLogger);
field public static final int DETECT_CUSTOM = 8; // 0x8
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index 2fc5808..c6d2bc8 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -171,7 +171,6 @@
showError("Error: unknown dispatch code '" + cmd + "'");
return;
}
-
final long now = SystemClock.uptimeMillis();
sendMediaKey(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keycode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
@@ -189,7 +188,6 @@
@Override
public void onSessionDestroyed() {
System.out.println("onSessionDestroyed. Enter q to quit.");
-
}
@Override
@@ -246,7 +244,7 @@
@Override
protected void onLooperPrepared() {
try {
- mController.registerCallbackListener(ControllerMonitor.this);
+ mController.registerCallbackListener(PACKAGE_NAME, ControllerMonitor.this);
} catch (RemoteException e) {
System.out.println("Error registering monitor callback");
}
@@ -266,13 +264,13 @@
} else if ("q".equals(line) || "quit".equals(line)) {
break;
} else if ("play".equals(line)) {
- mController.play(PACKAGE_NAME);
+ dispatchKeyCode(KeyEvent.KEYCODE_MEDIA_PLAY);
} else if ("pause".equals(line)) {
- mController.pause(PACKAGE_NAME);
+ dispatchKeyCode(KeyEvent.KEYCODE_MEDIA_PAUSE);
} else if ("next".equals(line)) {
- mController.next(PACKAGE_NAME);
+ dispatchKeyCode(KeyEvent.KEYCODE_MEDIA_NEXT);
} else if ("previous".equals(line)) {
- mController.previous(PACKAGE_NAME);
+ dispatchKeyCode(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
} else {
System.out.println("Invalid command: " + line);
}
@@ -295,6 +293,20 @@
}
}
}
+
+ private void dispatchKeyCode(int keyCode) {
+ final long now = SystemClock.uptimeMillis();
+ KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
+ KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD);
+ KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,
+ KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD);
+ try {
+ mController.sendMediaButton(PACKAGE_NAME, null, false, down);
+ mController.sendMediaButton(PACKAGE_NAME, null, false, up);
+ } catch (RemoteException e) {
+ System.out.println("Failed to dispatch " + keyCode);
+ }
+ }
}
private void runListSessions() {
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index c03340e..5662aea 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -28,6 +28,8 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManagerGlobal;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
@@ -47,6 +49,7 @@
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.accessibility.IAccessibilityInteractionConnection;
+import com.android.internal.util.function.pooled.PooledLambda;
import libcore.io.IoUtils;
import java.io.IOException;
@@ -118,10 +121,14 @@
private final ArrayList<AccessibilityEvent> mEventQueue = new ArrayList<AccessibilityEvent>();
- private final IAccessibilityServiceClient mClient;
+ private final Handler mLocalCallbackHandler;
private final IUiAutomationConnection mUiAutomationConnection;
+ private HandlerThread mRemoteCallbackThread;
+
+ private IAccessibilityServiceClient mClient;
+
private int mConnectionId = CONNECTION_ID_UNDEFINED;
private OnAccessibilityEventListener mOnAccessibilityEventListener;
@@ -190,8 +197,8 @@
if (connection == null) {
throw new IllegalArgumentException("Connection cannot be null!");
}
+ mLocalCallbackHandler = new Handler(looper);
mUiAutomationConnection = connection;
- mClient = new IAccessibilityServiceClientImpl(looper);
}
/**
@@ -217,6 +224,9 @@
return;
}
mIsConnecting = true;
+ mRemoteCallbackThread = new HandlerThread("UiAutomation");
+ mRemoteCallbackThread.start();
+ mClient = new IAccessibilityServiceClientImpl(mRemoteCallbackThread.getLooper());
}
try {
@@ -281,6 +291,9 @@
mUiAutomationConnection.disconnect();
} catch (RemoteException re) {
throw new RuntimeException("Error while disconnecting UiAutomation", re);
+ } finally {
+ mRemoteCallbackThread.quit();
+ mRemoteCallbackThread = null;
}
}
@@ -311,6 +324,7 @@
/**
* Sets a callback for observing the stream of {@link AccessibilityEvent}s.
+ * The callbacks are delivered on the main application thread.
*
* @param listener The callback.
*/
@@ -1139,17 +1153,21 @@
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
+ final OnAccessibilityEventListener listener;
synchronized (mLock) {
mLastEventTimeMillis = event.getEventTime();
if (mWaitingForEventDelivery) {
mEventQueue.add(AccessibilityEvent.obtain(event));
}
mLock.notifyAll();
+ listener = mOnAccessibilityEventListener;
}
- // Calling out only without a lock held.
- final OnAccessibilityEventListener listener = mOnAccessibilityEventListener;
if (listener != null) {
- listener.onAccessibilityEvent(AccessibilityEvent.obtain(event));
+ // Calling out only without a lock held.
+ mLocalCallbackHandler.post(PooledLambda.obtainRunnable(
+ OnAccessibilityEventListener::onAccessibilityEvent,
+ listener, AccessibilityEvent.obtain(event))
+ .recycleOnUse());
}
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 34ac9ae..c3548e5 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5574,8 +5574,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(anyOf = {Manifest.permission.SUSPEND_APPS,
- Manifest.permission.MANAGE_USERS})
+ @RequiresPermission(Manifest.permission.SUSPEND_APPS)
public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
@Nullable PersistableBundle appExtras, @Nullable PersistableBundle launcherExtras,
String dialogMessage) {
diff --git a/core/java/android/os/RemoteCallback.java b/core/java/android/os/RemoteCallback.java
index 7dbcb95..5914739 100644
--- a/core/java/android/os/RemoteCallback.java
+++ b/core/java/android/os/RemoteCallback.java
@@ -19,11 +19,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
/**
* @hide
*/
@SystemApi
+@TestApi
public final class RemoteCallback implements Parcelable {
public interface OnResultListener {
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
index 1811800c..26fb6b64 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -59,8 +59,11 @@
}
public boolean pulseOnPickupAvailable() {
- return mContext.getResources().getBoolean(R.bool.config_dozePulsePickup)
- && ambientDisplayAvailable();
+ return dozePulsePickupSensorAvailable() && ambientDisplayAvailable();
+ }
+
+ public boolean dozePulsePickupSensorAvailable() {
+ return mContext.getResources().getBoolean(R.bool.config_dozePulsePickup);
}
public boolean pulseOnPickupCanBeModified(int user) {
@@ -73,7 +76,11 @@
}
public boolean pulseOnDoubleTapAvailable() {
- return !TextUtils.isEmpty(doubleTapSensorType()) && ambientDisplayAvailable();
+ return doubleTapSensorAvailable() && ambientDisplayAvailable();
+ }
+
+ public boolean doubleTapSensorAvailable() {
+ return !TextUtils.isEmpty(doubleTapSensorType());
}
public String doubleTapSensorType() {
@@ -115,7 +122,7 @@
return boolSettingDefaultOff(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, user);
}
- private boolean ambientDisplayAvailable() {
+ public boolean ambientDisplayAvailable() {
return !TextUtils.isEmpty(ambientDisplayComponent());
}
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 9634c7f..626338d 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -17,6 +17,7 @@
import android.content.Intent;
import android.media.Rating;
+import android.media.session.ISessionControllerCallback;
import android.net.Uri;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -25,33 +26,46 @@
* @hide
*/
oneway interface ISessionCallback {
- void onCommand(String packageName, int pid, int uid, String command, in Bundle args,
- in ResultReceiver cb);
+ void onCommand(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ String command, in Bundle args, in ResultReceiver cb);
void onMediaButton(String packageName, int pid, int uid, in Intent mediaButtonIntent,
int sequenceNumber, in ResultReceiver cb);
+ void onMediaButtonFromController(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, in Intent mediaButtonIntent);
// These callbacks are for the TransportPerformer
- void onPrepare(String packageName, int pid, int uid);
- void onPrepareFromMediaId(String packageName, int pid, int uid, String mediaId,
- in Bundle extras);
- void onPrepareFromSearch(String packageName, int pid, int uid, String query, in Bundle extras);
- void onPrepareFromUri(String packageName, int pid, int uid, in Uri uri, in Bundle extras);
- void onPlay(String packageName, int pid, int uid);
- void onPlayFromMediaId(String packageName, int pid, int uid, String mediaId, in Bundle extras);
- void onPlayFromSearch(String packageName, int pid, int uid, String query, in Bundle extras);
- void onPlayFromUri(String packageName, int pid, int uid, in Uri uri, in Bundle extras);
- void onSkipToTrack(String packageName, int pid, int uid, long id);
- void onPause(String packageName, int pid, int uid);
- void onStop(String packageName, int pid, int uid);
- void onNext(String packageName, int pid, int uid);
- void onPrevious(String packageName, int pid, int uid);
- void onFastForward(String packageName, int pid, int uid);
- void onRewind(String packageName, int pid, int uid);
- void onSeekTo(String packageName, int pid, int uid, long pos);
- void onRate(String packageName, int pid, int uid, in Rating rating);
- void onCustomAction(String packageName, int pid, int uid, String action, in Bundle args);
+ void onPrepare(String packageName, int pid, int uid, ISessionControllerCallback caller);
+ void onPrepareFromMediaId(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, String mediaId, in Bundle extras);
+ void onPrepareFromSearch(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, String query, in Bundle extras);
+ void onPrepareFromUri(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ in Uri uri, in Bundle extras);
+ void onPlay(String packageName, int pid, int uid, ISessionControllerCallback caller);
+ void onPlayFromMediaId(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ String mediaId, in Bundle extras);
+ void onPlayFromSearch(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ String query, in Bundle extras);
+ void onPlayFromUri(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ in Uri uri, in Bundle extras);
+ void onSkipToTrack(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ long id);
+ void onPause(String packageName, int pid, int uid, ISessionControllerCallback caller);
+ void onStop(String packageName, int pid, int uid, ISessionControllerCallback caller);
+ void onNext(String packageName, int pid, int uid, ISessionControllerCallback caller);
+ void onPrevious(String packageName, int pid, int uid, ISessionControllerCallback caller);
+ void onFastForward(String packageName, int pid, int uid, ISessionControllerCallback caller);
+ void onRewind(String packageName, int pid, int uid, ISessionControllerCallback caller);
+ void onSeekTo(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ long pos);
+ void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ in Rating rating);
+ void onCustomAction(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ String action, in Bundle args);
// These callbacks are for volume handling
- void onAdjustVolume(String packageName, int pid, int uid, int direction);
- void onSetVolumeTo(String packageName, int pid, int uid, int value);
+ void onAdjustVolume(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ int direction);
+ void onSetVolumeTo(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, int value);
}
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index b4f52f9..861a8ce 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -32,42 +32,53 @@
import java.util.List;
/**
- * Interface to a MediaSession in the system.
+ * Interface to MediaSessionRecord in the system.
* @hide
*/
interface ISessionController {
- void sendCommand(String packageName, String command, in Bundle args, in ResultReceiver cb);
- boolean sendMediaButton(String packageName, boolean asSystemService, in KeyEvent mediaButton);
- void registerCallbackListener(in ISessionControllerCallback cb);
- void unregisterCallbackListener(in ISessionControllerCallback cb);
+ void sendCommand(String packageName, ISessionControllerCallback caller,
+ String command, in Bundle args, in ResultReceiver cb);
+ boolean sendMediaButton(String packageName, ISessionControllerCallback caller,
+ boolean asSystemService, in KeyEvent mediaButton);
+ void registerCallbackListener(String packageName, ISessionControllerCallback cb);
+ void unregisterCallbackListener(ISessionControllerCallback cb);
boolean isTransportControlEnabled();
String getPackageName();
String getTag();
PendingIntent getLaunchPendingIntent();
long getFlags();
ParcelableVolumeInfo getVolumeAttributes();
- void adjustVolume(String packageName, boolean asSystemService, int direction, int flags);
- void setVolumeTo(String packageName, int value, int flags);
+ void adjustVolume(String packageName, ISessionControllerCallback caller,
+ boolean asSystemService, int direction, int flags);
+ void setVolumeTo(String packageName, ISessionControllerCallback caller,
+ int value, int flags);
// These commands are for the TransportControls
- void prepare(String packageName);
- void prepareFromMediaId(String packageName, String mediaId, in Bundle extras);
- void prepareFromSearch(String packageName, String string, in Bundle extras);
- void prepareFromUri(String packageName, in Uri uri, in Bundle extras);
- void play(String packageName);
- void playFromMediaId(String packageName, String mediaId, in Bundle extras);
- void playFromSearch(String packageName, String string, in Bundle extras);
- void playFromUri(String packageName, in Uri uri, in Bundle extras);
- void skipToQueueItem(String packageName, long id);
- void pause(String packageName);
- void stop(String packageName);
- void next(String packageName);
- void previous(String packageName);
- void fastForward(String packageName);
- void rewind(String packageName);
- void seekTo(String packageName, long pos);
- void rate(String packageName, in Rating rating);
- void sendCustomAction(String packageName, String action, in Bundle args);
+ void prepare(String packageName, ISessionControllerCallback caller);
+ void prepareFromMediaId(String packageName, ISessionControllerCallback caller,
+ String mediaId, in Bundle extras);
+ void prepareFromSearch(String packageName, ISessionControllerCallback caller,
+ String string, in Bundle extras);
+ void prepareFromUri(String packageName, ISessionControllerCallback caller,
+ in Uri uri, in Bundle extras);
+ void play(String packageName, ISessionControllerCallback caller);
+ void playFromMediaId(String packageName, ISessionControllerCallback caller,
+ String mediaId, in Bundle extras);
+ void playFromSearch(String packageName, ISessionControllerCallback caller,
+ String string, in Bundle extras);
+ void playFromUri(String packageName, ISessionControllerCallback caller,
+ in Uri uri, in Bundle extras);
+ void skipToQueueItem(String packageName, ISessionControllerCallback caller, long id);
+ void pause(String packageName, ISessionControllerCallback caller);
+ void stop(String packageName, ISessionControllerCallback caller);
+ void next(String packageName, ISessionControllerCallback caller);
+ void previous(String packageName, ISessionControllerCallback caller);
+ void fastForward(String packageName, ISessionControllerCallback caller);
+ void rewind(String packageName, ISessionControllerCallback caller);
+ void seekTo(String packageName, ISessionControllerCallback caller, long pos);
+ void rate(String packageName, ISessionControllerCallback caller, in Rating rating);
+ void sendCustomAction(String packageName, ISessionControllerCallback caller,
+ String action, in Bundle args);
MediaMetadata getMetadata();
PlaybackState getPlaybackState();
ParceledListSlice getQueue();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 8c34a31..de22fa3 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -126,7 +126,7 @@
* @return true if the event was sent to the session, false otherwise.
*/
public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) {
- return dispatchMediButtonEventInternal(false, keyEvent);
+ return dispatchMediaButtonEventInternal(false, keyEvent);
}
/**
@@ -142,10 +142,10 @@
* @hide
*/
public boolean dispatchMediaButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
- return dispatchMediButtonEventInternal(true, keyEvent);
+ return dispatchMediaButtonEventInternal(true, keyEvent);
}
- private boolean dispatchMediButtonEventInternal(boolean asSystemService,
+ private boolean dispatchMediaButtonEventInternal(boolean asSystemService,
@NonNull KeyEvent keyEvent) {
if (keyEvent == null) {
throw new IllegalArgumentException("KeyEvent may not be null");
@@ -154,8 +154,8 @@
return false;
}
try {
- return mSessionBinder.sendMediaButton(mContext.getPackageName(), asSystemService,
- keyEvent);
+ return mSessionBinder.sendMediaButton(mContext.getPackageName(), mCbStub,
+ asSystemService, keyEvent);
} catch (RemoteException e) {
// System is dead. =(
}
@@ -189,7 +189,7 @@
break;
}
try {
- mSessionBinder.adjustVolume(mContext.getPackageName(), true, direction,
+ mSessionBinder.adjustVolume(mContext.getPackageName(), mCbStub, true, direction,
AudioManager.FLAG_SHOW_UI);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling adjustVolumeBy", e);
@@ -200,7 +200,7 @@
final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
| AudioManager.FLAG_FROM_KEY;
try {
- mSessionBinder.adjustVolume(mContext.getPackageName(), true, 0, flags);
+ mSessionBinder.adjustVolume(mContext.getPackageName(), mCbStub, true, 0, flags);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling adjustVolumeBy", e);
}
@@ -369,7 +369,7 @@
*/
public void setVolumeTo(int value, int flags) {
try {
- mSessionBinder.setVolumeTo(mContext.getPackageName(), value, flags);
+ mSessionBinder.setVolumeTo(mContext.getPackageName(), mCbStub, value, flags);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling setVolumeTo.", e);
}
@@ -390,7 +390,8 @@
*/
public void adjustVolume(int direction, int flags) {
try {
- mSessionBinder.adjustVolume(mContext.getPackageName(), false, direction, flags);
+ mSessionBinder.adjustVolume(mContext.getPackageName(), mCbStub, false, direction,
+ flags);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
}
@@ -456,7 +457,7 @@
throw new IllegalArgumentException("command cannot be null or empty");
}
try {
- mSessionBinder.sendCommand(mContext.getPackageName(), command, args, cb);
+ mSessionBinder.sendCommand(mContext.getPackageName(), mCbStub, command, args, cb);
} catch (RemoteException e) {
Log.d(TAG, "Dead object in sendCommand.", e);
}
@@ -521,7 +522,7 @@
if (!mCbRegistered) {
try {
- mSessionBinder.registerCallbackListener(mCbStub);
+ mSessionBinder.registerCallbackListener(mContext.getPackageName(), mCbStub);
mCbRegistered = true;
} catch (RemoteException e) {
Log.e(TAG, "Dead object in registerCallback", e);
@@ -668,7 +669,7 @@
*/
public void prepare() {
try {
- mSessionBinder.prepare(mContext.getPackageName());
+ mSessionBinder.prepare(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling prepare.", e);
}
@@ -692,7 +693,8 @@
"You must specify a non-empty String for prepareFromMediaId.");
}
try {
- mSessionBinder.prepareFromMediaId(mContext.getPackageName(), mediaId, extras);
+ mSessionBinder.prepareFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
+ extras);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e);
}
@@ -718,7 +720,7 @@
query = "";
}
try {
- mSessionBinder.prepareFromSearch(mContext.getPackageName(), query, extras);
+ mSessionBinder.prepareFromSearch(mContext.getPackageName(), mCbStub, query, extras);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
}
@@ -742,7 +744,7 @@
"You must specify a non-empty Uri for prepareFromUri.");
}
try {
- mSessionBinder.prepareFromUri(mContext.getPackageName(), uri, extras);
+ mSessionBinder.prepareFromUri(mContext.getPackageName(), mCbStub, uri, extras);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
}
@@ -753,7 +755,7 @@
*/
public void play() {
try {
- mSessionBinder.play(mContext.getPackageName());
+ mSessionBinder.play(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling play.", e);
}
@@ -772,7 +774,7 @@
"You must specify a non-empty String for playFromMediaId.");
}
try {
- mSessionBinder.playFromMediaId(mContext.getPackageName(), mediaId, extras);
+ mSessionBinder.playFromMediaId(mContext.getPackageName(), mCbStub, mediaId, extras);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling play(" + mediaId + ").", e);
}
@@ -794,7 +796,7 @@
query = "";
}
try {
- mSessionBinder.playFromSearch(mContext.getPackageName(), query, extras);
+ mSessionBinder.playFromSearch(mContext.getPackageName(), mCbStub, query, extras);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling play(" + query + ").", e);
}
@@ -813,7 +815,7 @@
"You must specify a non-empty Uri for playFromUri.");
}
try {
- mSessionBinder.playFromUri(mContext.getPackageName(), uri, extras);
+ mSessionBinder.playFromUri(mContext.getPackageName(), mCbStub, uri, extras);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling play(" + uri + ").", e);
}
@@ -825,7 +827,7 @@
*/
public void skipToQueueItem(long id) {
try {
- mSessionBinder.skipToQueueItem(mContext.getPackageName(), id);
+ mSessionBinder.skipToQueueItem(mContext.getPackageName(), mCbStub, id);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
}
@@ -837,7 +839,7 @@
*/
public void pause() {
try {
- mSessionBinder.pause(mContext.getPackageName());
+ mSessionBinder.pause(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling pause.", e);
}
@@ -849,7 +851,7 @@
*/
public void stop() {
try {
- mSessionBinder.stop(mContext.getPackageName());
+ mSessionBinder.stop(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling stop.", e);
}
@@ -862,7 +864,7 @@
*/
public void seekTo(long pos) {
try {
- mSessionBinder.seekTo(mContext.getPackageName(), pos);
+ mSessionBinder.seekTo(mContext.getPackageName(), mCbStub, pos);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling seekTo.", e);
}
@@ -874,7 +876,7 @@
*/
public void fastForward() {
try {
- mSessionBinder.fastForward(mContext.getPackageName());
+ mSessionBinder.fastForward(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling fastForward.", e);
}
@@ -885,7 +887,7 @@
*/
public void skipToNext() {
try {
- mSessionBinder.next(mContext.getPackageName());
+ mSessionBinder.next(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling next.", e);
}
@@ -897,7 +899,7 @@
*/
public void rewind() {
try {
- mSessionBinder.rewind(mContext.getPackageName());
+ mSessionBinder.rewind(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling rewind.", e);
}
@@ -908,7 +910,7 @@
*/
public void skipToPrevious() {
try {
- mSessionBinder.previous(mContext.getPackageName());
+ mSessionBinder.previous(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling previous.", e);
}
@@ -923,7 +925,7 @@
*/
public void setRating(Rating rating) {
try {
- mSessionBinder.rate(mContext.getPackageName(), rating);
+ mSessionBinder.rate(mContext.getPackageName(), mCbStub, rating);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling rate.", e);
}
@@ -937,7 +939,7 @@
* custom action.
*/
public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction,
- @Nullable Bundle args) {
+ @Nullable Bundle args) {
if (customAction == null) {
throw new IllegalArgumentException("CustomAction cannot be null.");
}
@@ -958,7 +960,7 @@
throw new IllegalArgumentException("CustomAction cannot be null.");
}
try {
- mSessionBinder.sendCustomAction(mContext.getPackageName(), action, args);
+ mSessionBinder.sendCustomAction(mContext.getPackageName(), mCbStub, action, args);
} catch (RemoteException e) {
Log.d(TAG, "Dead object in sendCustomAction.", e);
}
@@ -1124,8 +1126,8 @@
public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) {
MediaController controller = mController.get();
if (controller != null) {
- PlaybackInfo info = new PlaybackInfo(pvi.volumeType, pvi.audioAttrs, pvi.controlType,
- pvi.maxVolume, pvi.currentVolume);
+ PlaybackInfo info = new PlaybackInfo(pvi.volumeType, pvi.audioAttrs,
+ pvi.controlType, pvi.maxVolume, pvi.currentVolume);
controller.postMessage(MSG_UPDATE_VOLUME, info, null);
}
}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 6f4f20e..fad7e3f 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -43,6 +43,7 @@
import android.service.media.MediaBrowserService;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import android.view.KeyEvent;
import android.view.ViewConfiguration;
@@ -122,15 +123,6 @@
FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
public @interface SessionFlags { }
- private static final String EXTRA_KEY_CALLING_PACKAGE =
- "android.media.session.extra.CALLING_PACKAGE";
- private static final String EXTRA_KEY_CALLING_PID =
- "android.media.session.extra.CALLING_PID";
- private static final String EXTRA_KEY_CALLING_UID =
- "android.media.session.extra.CALLING_UID";
- private static final String EXTRA_KEY_ORIGINAL_BUNDLE =
- "android.media.session.extra.ORIGINAL_BUNDLE";
-
private final Object mLock = new Object();
private final int mMaxBitmapSize;
@@ -529,15 +521,11 @@
* @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
*/
public final @NonNull RemoteUserInfo getCurrentControllerInfo() {
- return createRemoteUserInfo(getCurrentData());
- }
-
- private @NonNull Bundle getCurrentData() {
- if (mCallback == null || mCallback.mCurrentData == null) {
+ if (mCallback == null || mCallback.mCurrentControllerInfo == null) {
throw new IllegalStateException(
"This should be called inside of MediaSession.Callback methods");
}
- return mCallback.mCurrentData;
+ return mCallback.mCurrentControllerInfo;
}
/**
@@ -568,161 +556,122 @@
* @hide
*/
public String getCallingPackage() {
- if (mCallback != null) {
- return createRemoteUserInfo(mCallback.mCurrentData).getPackageName();
+ if (mCallback != null && mCallback.mCurrentControllerInfo != null) {
+ return mCallback.mCurrentControllerInfo.getPackageName();
}
return null;
}
- private void dispatchPrepare(Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_PREPARE, null, extras);
+ private void dispatchPrepare(RemoteUserInfo caller) {
+ postToCallback(caller, CallbackMessageHandler.MSG_PREPARE, null, null);
}
- private void dispatchPrepareFromMediaId(String mediaId, Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
+ private void dispatchPrepareFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
+ postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
}
- private void dispatchPrepareFromSearch(String query, Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
+ private void dispatchPrepareFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
+ postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
}
- private void dispatchPrepareFromUri(Uri uri, Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
+ private void dispatchPrepareFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
+ postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
}
- private void dispatchPlay(Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_PLAY, null, extras);
+ private void dispatchPlay(RemoteUserInfo caller) {
+ postToCallback(caller, CallbackMessageHandler.MSG_PLAY, null, null);
}
- private void dispatchPlayFromMediaId(String mediaId, Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
+ private void dispatchPlayFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
+ postToCallback(caller, CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
}
- private void dispatchPlayFromSearch(String query, Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
+ private void dispatchPlayFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
+ postToCallback(caller, CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
}
- private void dispatchPlayFromUri(Uri uri, Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
+ private void dispatchPlayFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
+ postToCallback(caller, CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
}
- private void dispatchSkipToItem(long id, Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, extras);
+ private void dispatchSkipToItem(RemoteUserInfo caller, long id) {
+ postToCallback(caller, CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, null);
}
- private void dispatchPause(Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_PAUSE, null, extras);
+ private void dispatchPause(RemoteUserInfo caller) {
+ postToCallback(caller, CallbackMessageHandler.MSG_PAUSE, null, null);
}
- private void dispatchStop(Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_STOP, null, extras);
+ private void dispatchStop(RemoteUserInfo caller) {
+ postToCallback(caller, CallbackMessageHandler.MSG_STOP, null, null);
}
- private void dispatchNext(Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_NEXT, null, extras);
+ private void dispatchNext(RemoteUserInfo caller) {
+ postToCallback(caller, CallbackMessageHandler.MSG_NEXT, null, null);
}
- private void dispatchPrevious(Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_PREVIOUS, null, extras);
+ private void dispatchPrevious(RemoteUserInfo caller) {
+ postToCallback(caller, CallbackMessageHandler.MSG_PREVIOUS, null, null);
}
- private void dispatchFastForward(Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_FAST_FORWARD, null, extras);
+ private void dispatchFastForward(RemoteUserInfo caller) {
+ postToCallback(caller, CallbackMessageHandler.MSG_FAST_FORWARD, null, null);
}
- private void dispatchRewind(Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_REWIND, null, extras);
+ private void dispatchRewind(RemoteUserInfo caller) {
+ postToCallback(caller, CallbackMessageHandler.MSG_REWIND, null, null);
}
- private void dispatchSeekTo(long pos, Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_SEEK_TO, pos, extras);
+ private void dispatchSeekTo(RemoteUserInfo caller, long pos) {
+ postToCallback(caller, CallbackMessageHandler.MSG_SEEK_TO, pos, null);
}
- private void dispatchRate(Rating rating, Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_RATE, rating, extras);
+ private void dispatchRate(RemoteUserInfo caller, Rating rating) {
+ postToCallback(caller, CallbackMessageHandler.MSG_RATE, rating, null);
}
- private void dispatchCustomAction(String action, Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_CUSTOM_ACTION, action, extras);
+ private void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) {
+ postToCallback(caller, CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
}
- private void dispatchMediaButton(Intent mediaButtonIntent, Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, extras);
+ private void dispatchMediaButton(RemoteUserInfo caller, Intent mediaButtonIntent) {
+ postToCallback(caller, CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, null);
}
- private void dispatchAdjustVolume(int direction, Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, extras);
+ private void dispatchMediaButtonDelayed(RemoteUserInfo info, Intent mediaButtonIntent,
+ long delay) {
+ postToCallbackDelayed(info, CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
+ mediaButtonIntent, null, delay);
}
- private void dispatchSetVolumeTo(int volume, Bundle extras) {
- postToCallback(CallbackMessageHandler.MSG_SET_VOLUME, volume, extras);
+ private void dispatchAdjustVolume(RemoteUserInfo caller, int direction) {
+ postToCallback(caller, CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, null);
}
- private void postCommand(String command, Bundle args, ResultReceiver resultCb, Bundle extras) {
+ private void dispatchSetVolumeTo(RemoteUserInfo caller, int volume) {
+ postToCallback(caller, CallbackMessageHandler.MSG_SET_VOLUME, volume, null);
+ }
+
+ private void dispatchCommand(RemoteUserInfo caller, String command, Bundle args,
+ ResultReceiver resultCb) {
Command cmd = new Command(command, args, resultCb);
- postToCallback(CallbackMessageHandler.MSG_COMMAND, cmd, extras);
+ postToCallback(caller, CallbackMessageHandler.MSG_COMMAND, cmd, null);
}
- private void postToCallback(int what, Object obj, Bundle extras) {
+ private void postToCallback(RemoteUserInfo caller, int what, Object obj, Bundle data) {
+ postToCallbackDelayed(caller, what, obj, data, 0);
+ }
+
+ private void postToCallbackDelayed(RemoteUserInfo caller, int what, Object obj, Bundle data,
+ long delay) {
synchronized (mLock) {
if (mCallback != null) {
- mCallback.post(what, obj, extras);
+ mCallback.post(caller, what, obj, data, delay);
}
}
}
/**
- * Creates the extra bundle that includes the caller information.
- *
- * @return An extraBundle that contains caller information
- */
- private static Bundle createExtraBundle(String packageName, int pid, int uid) {
- return createExtraBundle(packageName, pid, uid, null);
- }
-
- /**
- * Creates the extra bundle that includes the caller information.
- *
- * @param originalBundle bundle
- * @return An extraBundle that contains caller information
- */
- private static Bundle createExtraBundle(String packageName, int pid, int uid,
- Bundle originalBundle) {
- Bundle bundle = new Bundle();
- bundle.putString(EXTRA_KEY_CALLING_PACKAGE, packageName);
- bundle.putInt(EXTRA_KEY_CALLING_PID, pid);
- bundle.putInt(EXTRA_KEY_CALLING_UID, uid);
- if (originalBundle != null) {
- bundle.putBundle(EXTRA_KEY_ORIGINAL_BUNDLE, originalBundle);
- }
- return bundle;
- }
-
- /**
- * Creates the {@link RemoteUserInfo} from the extra bundle created by
- * {@link #createExtraBundle}.
- *
- * @param extraBundle that previously created by createExtraBundle()
- * @return a RemoteUserInfo
- */
- private static RemoteUserInfo createRemoteUserInfo(Bundle extraBundle) {
- return new RemoteUserInfo(
- extraBundle.getString(EXTRA_KEY_CALLING_PACKAGE),
- extraBundle.getInt(EXTRA_KEY_CALLING_PID, INVALID_PID),
- extraBundle.getInt(EXTRA_KEY_CALLING_UID, INVALID_UID));
- }
-
- /**
- * Gets the original bundle from the extra bundle created by {@link #createExtraBundle}.
- *
- * @param extraBundle that previously created by createExtraBundle()
- * @return a Bundle
- */
- private static Bundle getOriginalBundle(Bundle extraBundle) {
- return extraBundle.getBundle(EXTRA_KEY_ORIGINAL_BUNDLE);
- }
-
- /**
* Return true if this is considered an active playback state.
*
* @hide
@@ -872,10 +821,9 @@
}
} else {
mMediaPlayPauseKeyPending = true;
- mHandler.postDelayed(CallbackMessageHandler
- .MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
- mSession.getCurrentData(),
- ViewConfiguration.getDoubleTapTimeout());
+ mSession.dispatchMediaButtonDelayed(
+ mSession.getCurrentControllerInfo(),
+ mediaButtonIntent, ViewConfiguration.getDoubleTapTimeout());
}
return true;
default:
@@ -1109,12 +1057,19 @@
mMediaSession = new WeakReference<>(session);
}
+ private static RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid,
+ ISessionControllerCallback caller) {
+ return new RemoteUserInfo(packageName, pid, uid,
+ caller != null ? caller.asBinder() : null);
+ }
+
@Override
- public void onCommand(String packageName, int pid, int uid, String command, Bundle args,
- ResultReceiver cb) {
+ public void onCommand(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, String command, Bundle args, ResultReceiver cb) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.postCommand(command, args, cb, createExtraBundle(packageName, pid, uid));
+ session.dispatchCommand(createRemoteUserInfo(packageName, pid, uid, caller),
+ command, args, cb);
}
}
@@ -1124,8 +1079,8 @@
MediaSession session = mMediaSession.get();
try {
if (session != null) {
- session.dispatchMediaButton(
- mediaButtonIntent, createExtraBundle(packageName, pid, uid));
+ session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, null),
+ mediaButtonIntent);
}
} finally {
if (cb != null) {
@@ -1135,173 +1090,205 @@
}
@Override
- public void onPrepare(String packageName, int pid, int uid) {
+ public void onMediaButtonFromController(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, Intent mediaButtonIntent) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchPrepare(createExtraBundle(packageName, pid, uid));
+ session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, caller),
+ mediaButtonIntent);
}
}
@Override
- public void onPrepareFromMediaId(String packageName, int pid, int uid, String mediaId,
+ public void onPrepare(String packageName, int pid, int uid,
+ ISessionControllerCallback caller) {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid, caller));
+ }
+ }
+
+ @Override
+ public void onPrepareFromMediaId(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, String mediaId,
Bundle extras) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchPrepareFromMediaId(
- mediaId, createExtraBundle(packageName, pid, uid, extras));
+ createRemoteUserInfo(packageName, pid, uid, caller), mediaId, extras);
}
}
@Override
- public void onPrepareFromSearch(String packageName, int pid, int uid, String query,
+ public void onPrepareFromSearch(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, String query,
Bundle extras) {
MediaSession session = mMediaSession.get();
if (session != null) {
session.dispatchPrepareFromSearch(
- query, createExtraBundle(packageName, pid, uid, extras));
+ createRemoteUserInfo(packageName, pid, uid, caller), query, extras);
}
}
@Override
- public void onPrepareFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
+ public void onPrepareFromUri(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, Uri uri, Bundle extras) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchPrepareFromUri(uri,
- createExtraBundle(packageName, pid, uid, extras));
+ session.dispatchPrepareFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
+ uri, extras);
}
}
@Override
- public void onPlay(String packageName, int pid, int uid) {
+ public void onPlay(String packageName, int pid, int uid,
+ ISessionControllerCallback caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchPlay(createExtraBundle(packageName, pid, uid));
+ session.dispatchPlay(createRemoteUserInfo(packageName, pid, uid, caller));
}
}
@Override
- public void onPlayFromMediaId(String packageName, int pid, int uid, String mediaId,
+ public void onPlayFromMediaId(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, String mediaId,
Bundle extras) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchPlayFromMediaId(
- mediaId, createExtraBundle(packageName, pid, uid, extras));
+ session.dispatchPlayFromMediaId(createRemoteUserInfo(packageName, pid, uid, caller),
+ mediaId, extras);
}
}
@Override
- public void onPlayFromSearch(String packageName, int pid, int uid, String query,
+ public void onPlayFromSearch(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, String query,
Bundle extras) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchPlayFromSearch(query, createExtraBundle(packageName, pid, uid,
- extras));
+ session.dispatchPlayFromSearch(createRemoteUserInfo(packageName, pid, uid, caller),
+ query, extras);
}
}
@Override
- public void onPlayFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
+ public void onPlayFromUri(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, Uri uri, Bundle extras) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchPlayFromUri(uri, createExtraBundle(packageName, pid, uid, extras));
+ session.dispatchPlayFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
+ uri, extras);
}
}
@Override
- public void onSkipToTrack(String packageName, int pid, int uid, long id) {
+ public void onSkipToTrack(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, long id) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchSkipToItem(id, createExtraBundle(packageName, pid, uid));
+ session.dispatchSkipToItem(createRemoteUserInfo(packageName, pid, uid, caller), id);
}
}
@Override
- public void onPause(String packageName, int pid, int uid) {
+ public void onPause(String packageName, int pid, int uid,
+ ISessionControllerCallback caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchPause(createExtraBundle(packageName, pid, uid));
+ session.dispatchPause(createRemoteUserInfo(packageName, pid, uid, caller));
}
}
@Override
- public void onStop(String packageName, int pid, int uid) {
+ public void onStop(String packageName, int pid, int uid,
+ ISessionControllerCallback caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchStop(createExtraBundle(packageName, pid, uid));
+ session.dispatchStop(createRemoteUserInfo(packageName, pid, uid, caller));
}
}
@Override
- public void onNext(String packageName, int pid, int uid) {
+ public void onNext(String packageName, int pid, int uid,
+ ISessionControllerCallback caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchNext(createExtraBundle(packageName, pid, uid));
+ session.dispatchNext(createRemoteUserInfo(packageName, pid, uid, caller));
}
}
@Override
- public void onPrevious(String packageName, int pid, int uid) {
+ public void onPrevious(String packageName, int pid, int uid,
+ ISessionControllerCallback caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchPrevious(createExtraBundle(packageName, pid, uid));
+ session.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid, caller));
}
}
@Override
- public void onFastForward(String packageName, int pid, int uid) {
+ public void onFastForward(String packageName, int pid, int uid,
+ ISessionControllerCallback caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchFastForward(createExtraBundle(packageName, pid, uid));
+ session.dispatchFastForward(createRemoteUserInfo(packageName, pid, uid, caller));
}
}
@Override
- public void onRewind(String packageName, int pid, int uid) {
+ public void onRewind(String packageName, int pid, int uid,
+ ISessionControllerCallback caller) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchRewind(createExtraBundle(packageName, pid, uid));
+ session.dispatchRewind(createRemoteUserInfo(packageName, pid, uid, caller));
}
}
@Override
- public void onSeekTo(String packageName, int pid, int uid, long pos) {
+ public void onSeekTo(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, long pos) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchSeekTo(pos, createExtraBundle(packageName, pid, uid));
+ session.dispatchSeekTo(createRemoteUserInfo(packageName, pid, uid, caller), pos);
}
}
@Override
- public void onRate(String packageName, int pid, int uid, Rating rating) {
+ public void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ Rating rating) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchRate(rating, createExtraBundle(packageName, pid, uid));
+ session.dispatchRate(createRemoteUserInfo(packageName, pid, uid, caller), rating);
}
}
@Override
- public void onCustomAction(String packageName, int pid, int uid, String action,
- Bundle args) {
+ public void onCustomAction(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, String action, Bundle args) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchCustomAction(
- action, createExtraBundle(packageName, pid, uid, args));
+ session.dispatchCustomAction(createRemoteUserInfo(packageName, pid, uid, caller),
+ action, args);
}
}
@Override
- public void onAdjustVolume(String packageName, int pid, int uid, int direction) {
+ public void onAdjustVolume(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, int direction) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchAdjustVolume(direction, createExtraBundle(packageName, pid, uid));
+ session.dispatchAdjustVolume(createRemoteUserInfo(packageName, pid, uid, caller),
+ direction);
}
}
@Override
- public void onSetVolumeTo(String packageName, int pid, int uid, int value) {
+ public void onSetVolumeTo(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, int value) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchSetVolumeTo(value, createExtraBundle(packageName, pid, uid));
+ session.dispatchSetVolumeTo(createRemoteUserInfo(packageName, pid, uid, caller),
+ value);
}
}
}
@@ -1424,7 +1411,6 @@
}
private class CallbackMessageHandler extends Handler {
-
private static final int MSG_COMMAND = 1;
private static final int MSG_MEDIA_BUTTON = 2;
private static final int MSG_PREPARE = 3;
@@ -1450,7 +1436,7 @@
private static final int MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT = 23;
private MediaSession.Callback mCallback;
- private Bundle mCurrentData;
+ private RemoteUserInfo mCurrentControllerInfo;
public CallbackMessageHandler(Looper looper, MediaSession.Callback callback) {
super(looper, null, true);
@@ -1458,60 +1444,58 @@
mCallback.mHandler = this;
}
- public void post(int what, Object obj, Bundle data) {
- Message msg = obtainMessage(what, obj);
+ public void post(RemoteUserInfo caller, int what, Object obj, Bundle data, long delayMs) {
+ Pair<RemoteUserInfo, Object> objWithCaller = Pair.create(caller, obj);
+ Message msg = obtainMessage(what, objWithCaller);
msg.setData(data);
- msg.sendToTarget();
- }
-
- public void postDelayed(int what, Bundle data, long delayMs) {
- Message msg = obtainMessage(what);
- msg.setData(data);
- sendMessageDelayed(msg, delayMs);
+ if (delayMs > 0) {
+ sendMessageDelayed(msg, delayMs);
+ } else {
+ sendMessage(msg);
+ }
}
@Override
public void handleMessage(Message msg) {
- VolumeProvider vp;
- Bundle data = msg.getData();
- Bundle originalBundle = getOriginalBundle(data);
+ mCurrentControllerInfo = ((Pair<RemoteUserInfo, Object>) msg.obj).first;
- mCurrentData = data;
+ VolumeProvider vp;
+ Object obj = ((Pair<RemoteUserInfo, Object>) msg.obj).second;
switch (msg.what) {
case MSG_COMMAND:
- Command cmd = (Command) msg.obj;
+ Command cmd = (Command) obj;
mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
break;
case MSG_MEDIA_BUTTON:
- mCallback.onMediaButtonEvent((Intent) msg.obj);
+ mCallback.onMediaButtonEvent((Intent) obj);
break;
case MSG_PREPARE:
mCallback.onPrepare();
break;
case MSG_PREPARE_MEDIA_ID:
- mCallback.onPrepareFromMediaId((String) msg.obj, originalBundle);
+ mCallback.onPrepareFromMediaId((String) obj, msg.getData());
break;
case MSG_PREPARE_SEARCH:
- mCallback.onPrepareFromSearch((String) msg.obj, originalBundle);
+ mCallback.onPrepareFromSearch((String) obj, msg.getData());
break;
case MSG_PREPARE_URI:
- mCallback.onPrepareFromUri((Uri) msg.obj, originalBundle);
+ mCallback.onPrepareFromUri((Uri) obj, msg.getData());
break;
case MSG_PLAY:
mCallback.onPlay();
break;
case MSG_PLAY_MEDIA_ID:
- mCallback.onPlayFromMediaId((String) msg.obj, originalBundle);
+ mCallback.onPlayFromMediaId((String) obj, msg.getData());
break;
case MSG_PLAY_SEARCH:
- mCallback.onPlayFromSearch((String) msg.obj, originalBundle);
+ mCallback.onPlayFromSearch((String) obj, msg.getData());
break;
case MSG_PLAY_URI:
- mCallback.onPlayFromUri((Uri) msg.obj, originalBundle);
+ mCallback.onPlayFromUri((Uri) obj, msg.getData());
break;
case MSG_SKIP_TO_ITEM:
- mCallback.onSkipToQueueItem((Long) msg.obj);
+ mCallback.onSkipToQueueItem((Long) obj);
break;
case MSG_PAUSE:
mCallback.onPause();
@@ -1532,20 +1516,20 @@
mCallback.onRewind();
break;
case MSG_SEEK_TO:
- mCallback.onSeekTo((Long) msg.obj);
+ mCallback.onSeekTo((Long) obj);
break;
case MSG_RATE:
- mCallback.onSetRating((Rating) msg.obj);
+ mCallback.onSetRating((Rating) obj);
break;
case MSG_CUSTOM_ACTION:
- mCallback.onCustomAction((String) msg.obj, originalBundle);
+ mCallback.onCustomAction((String) obj, msg.getData());
break;
case MSG_ADJUST_VOLUME:
synchronized (mLock) {
vp = mVolumeProvider;
}
if (vp != null) {
- vp.onAdjustVolume((int) msg.obj);
+ vp.onAdjustVolume((int) obj);
}
break;
case MSG_SET_VOLUME:
@@ -1553,14 +1537,14 @@
vp = mVolumeProvider;
}
if (vp != null) {
- vp.onSetVolumeTo((int) msg.obj);
+ vp.onSetVolumeTo((int) obj);
}
break;
case MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT:
mCallback.handleMediaPlayPauseKeySingleTapIfPending();
break;
}
- mCurrentData = null;
+ mCurrentControllerInfo = null;
}
}
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index f54bfc1..3f0b6c5 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -30,6 +30,7 @@
import android.media.MediaSession2;
import android.media.MediaSessionService2;
import android.media.SessionToken2;
+import android.media.browse.MediaBrowser;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -818,19 +819,31 @@
/**
* Information of a remote user of {@link MediaSession} or {@link MediaBrowserService}.
- * This can be used to decide whether the remote user is trusted app.
+ * This can be used to decide whether the remote user is trusted app, and also differentiate
+ * caller of {@link MediaSession} and {@link MediaBrowserService} callbacks.
+ * <p>
+ * See {@link #equals(Object)} to take a look at how it differentiate media controller.
*
* @see #isTrustedForMediaControl(RemoteUserInfo)
*/
public static final class RemoteUserInfo {
- private String mPackageName;
- private int mPid;
- private int mUid;
+ private final String mPackageName;
+ private final int mPid;
+ private final int mUid;
+ private final IBinder mCallerBinder;
- public RemoteUserInfo(String packageName, int pid, int uid) {
+ public RemoteUserInfo(@NonNull String packageName, int pid, int uid) {
+ this(packageName, pid, uid, null);
+ }
+
+ /**
+ * @hide
+ */
+ public RemoteUserInfo(String packageName, int pid, int uid, IBinder callerBinder) {
mPackageName = packageName;
mPid = pid;
mUid = uid;
+ mCallerBinder = callerBinder;
}
/**
@@ -854,15 +867,29 @@
return mUid;
}
+ /**
+ * Returns equality of two RemoteUserInfo. Two RemoteUserInfos are the same only if they're
+ * sent to the same controller (either {@link MediaController} or
+ * {@link MediaBrowser}. If it's not nor one of them is triggered by the key presses, they
+ * would be considered as different one.
+ * <p>
+ * If you only want to compare the caller's package, compare them with the
+ * {@link #getPackageName()}, {@link #getPid()}, and/or {@link #getUid()} directly.
+ *
+ * @param obj the reference object with which to compare.
+ * @return {@code true} if equals, {@code false} otherwise
+ */
@Override
public boolean equals(Object obj) {
if (!(obj instanceof RemoteUserInfo)) {
return false;
}
+ if (this == obj) {
+ return true;
+ }
RemoteUserInfo otherUserInfo = (RemoteUserInfo) obj;
- return TextUtils.equals(mPackageName, otherUserInfo.mPackageName)
- && mPid == otherUserInfo.mPid
- && mUid == otherUserInfo.mUid;
+ return (mCallerBinder == null || otherUserInfo.mCallerBinder == null) ? false
+ : mCallerBinder.equals(otherUserInfo.mCallerBinder);
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 4e9e566..0b58c9d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -505,5 +505,6 @@
callback.onProfileConnectionStateChanged(device, state, bluetoothProfile);
}
}
+ mDeviceManager.onProfileConnectionStateChanged(device, state, bluetoothProfile);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 15f6983..e9d96ae 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -19,6 +19,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.util.Log;
@@ -323,16 +324,31 @@
if (cachedDevice.getHiSyncId() == hiSyncId) {
if (firstMatchedIndex != -1) {
/* Found the second one */
- mCachedDevices.remove(i);
- mHearingAidDevicesNotAddedInCache.add(cachedDevice);
+ int indexToRemoveFromUi;
+ CachedBluetoothDevice deviceToRemoveFromUi;
+
// Since the hiSyncIds have been updated for a connected pair of hearing aids,
// we remove the entry of one the hearing aids from the UI. Unless the
- // hiSyncId get updated, the system does not know its a hearing aid, so we add
+ // hiSyncId get updated, the system does not know it is a hearing aid, so we add
// both the hearing aids as separate entries in the UI first, then remove one
- // of them after the hiSyncId is populated.
- log("onHiSyncIdChanged: removed device=" + cachedDevice + ", with hiSyncId="
- + hiSyncId);
- mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
+ // of them after the hiSyncId is populated. We will choose the device that
+ // is not connected to be removed.
+ if (cachedDevice.isConnected()) {
+ indexToRemoveFromUi = firstMatchedIndex;
+ deviceToRemoveFromUi = mCachedDevices.get(firstMatchedIndex);
+ mCachedDevicesMapForHearingAids.put(hiSyncId, cachedDevice);
+ } else {
+ indexToRemoveFromUi = i;
+ deviceToRemoveFromUi = cachedDevice;
+ mCachedDevicesMapForHearingAids.put(hiSyncId,
+ mCachedDevices.get(firstMatchedIndex));
+ }
+
+ mCachedDevices.remove(indexToRemoveFromUi);
+ mHearingAidDevicesNotAddedInCache.add(deviceToRemoveFromUi);
+ log("onHiSyncIdChanged: removed from UI device=" + deviceToRemoveFromUi
+ + ", with hiSyncId=" + hiSyncId);
+ mBtManager.getEventManager().dispatchDeviceRemoved(deviceToRemoveFromUi);
break;
} else {
mCachedDevicesMapForHearingAids.put(hiSyncId, cachedDevice);
@@ -342,6 +358,72 @@
}
}
+ private CachedBluetoothDevice getHearingAidOtherDevice(CachedBluetoothDevice thisDevice,
+ long hiSyncId) {
+ if (hiSyncId == BluetoothHearingAid.HI_SYNC_ID_INVALID) {
+ return null;
+ }
+
+ // Searched the lists for the other side device with the matching hiSyncId.
+ for (CachedBluetoothDevice notCachedDevice : mHearingAidDevicesNotAddedInCache) {
+ if ((hiSyncId == notCachedDevice.getHiSyncId()) &&
+ (!Objects.equals(notCachedDevice, thisDevice))) {
+ return notCachedDevice;
+ }
+ }
+
+ CachedBluetoothDevice cachedDevice = mCachedDevicesMapForHearingAids.get(hiSyncId);
+ if (!Objects.equals(cachedDevice, thisDevice)) {
+ return cachedDevice;
+ }
+ return null;
+ }
+
+ private void hearingAidSwitchDisplayDevice(CachedBluetoothDevice toDisplayDevice,
+ CachedBluetoothDevice toHideDevice, long hiSyncId)
+ {
+ log("hearingAidSwitchDisplayDevice: toDisplayDevice=" + toDisplayDevice
+ + ", toHideDevice=" + toHideDevice);
+
+ // Remove the "toHideDevice" device from the UI.
+ mHearingAidDevicesNotAddedInCache.add(toHideDevice);
+ mCachedDevices.remove(toHideDevice);
+ mBtManager.getEventManager().dispatchDeviceRemoved(toHideDevice);
+
+ // Add the "toDisplayDevice" device to the UI.
+ mHearingAidDevicesNotAddedInCache.remove(toDisplayDevice);
+ mCachedDevices.add(toDisplayDevice);
+ mCachedDevicesMapForHearingAids.put(hiSyncId, toDisplayDevice);
+ mBtManager.getEventManager().dispatchDeviceAdded(toDisplayDevice);
+ }
+
+ public synchronized void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice,
+ int state, int bluetoothProfile) {
+ if (bluetoothProfile == BluetoothProfile.HEARING_AID
+ && cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID
+ && cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
+
+ long hiSyncId = cachedDevice.getHiSyncId();
+
+ CachedBluetoothDevice otherDevice = getHearingAidOtherDevice(cachedDevice, hiSyncId);
+ if (otherDevice == null) {
+ // no other side device. Nothing to do.
+ return;
+ }
+
+ if (state == BluetoothProfile.STATE_CONNECTED &&
+ mHearingAidDevicesNotAddedInCache.contains(cachedDevice)) {
+ hearingAidSwitchDisplayDevice(cachedDevice, otherDevice, hiSyncId);
+ } else if (state == BluetoothProfile.STATE_DISCONNECTED
+ && otherDevice.isConnected()) {
+ CachedBluetoothDevice mapDevice = mCachedDevicesMapForHearingAids.get(hiSyncId);
+ if ((mapDevice != null) && (Objects.equals(cachedDevice, mapDevice))) {
+ hearingAidSwitchDisplayDevice(otherDevice, cachedDevice, hiSyncId);
+ }
+ }
+ }
+ }
+
public synchronized void onDeviceUnpaired(CachedBluetoothDevice device) {
final long hiSyncId = device.getHiSyncId();
@@ -353,9 +435,16 @@
// TODO: Look for more cleanups on unpairing the device.
mHearingAidDevicesNotAddedInCache.remove(i);
if (device == cachedDevice) continue;
+ log("onDeviceUnpaired: Unpair device=" + cachedDevice);
cachedDevice.unpair();
}
}
+
+ CachedBluetoothDevice mappedDevice = mCachedDevicesMapForHearingAids.get(hiSyncId);
+ if ((mappedDevice != null) && (!Objects.equals(device, mappedDevice))) {
+ log("onDeviceUnpaired: Unpair mapped device=" + mappedDevice);
+ mappedDevice.unpair();
+ }
}
public synchronized void dispatchAudioModeChanged() {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index 466980c..1080690 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -98,5 +98,8 @@
verify(mBluetoothCallback).onProfileConnectionStateChanged(mCachedBluetoothDevice,
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP);
+
+ verify(mCachedDeviceManager).onProfileConnectionStateChanged(mCachedBluetoothDevice,
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index bab3cab..16ed85c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -235,7 +235,7 @@
* Test to verify onHiSyncIdChanged() for hearing aid devices with same HiSyncId.
*/
@Test
- public void testOnDeviceAdded_sameHiSyncId_populateInDifferentLists() {
+ public void testOnHiSyncIdChanged_sameHiSyncId_populateInDifferentLists() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
mLocalProfileManager, mDevice1);
assertThat(cachedDevice1).isNotNull();
@@ -261,16 +261,53 @@
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).hasSize(1);
Collection<CachedBluetoothDevice> devices = mCachedDeviceManager.getCachedDevicesCopy();
assertThat(devices).contains(cachedDevice2);
- assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids.values())
- .contains(cachedDevice2);
- assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).contains(cachedDevice1);
+ assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids)
+ .containsKey(HISYNCID1);
+ }
+
+ /**
+ * Test to verify onHiSyncIdChanged() for 2 hearing aid devices with same HiSyncId but one
+ * device is connected and other is disconnected. The connected device should be chosen.
+ */
+ @Test
+ public void testOnHiSyncIdChanged_sameHiSyncIdAndOneConnected_chooseConnectedDevice() {
+ CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
+ mLocalProfileManager, mDevice1);
+ assertThat(cachedDevice1).isNotNull();
+ CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
+ mLocalProfileManager, mDevice2);
+ assertThat(cachedDevice2).isNotNull();
+ cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+ cachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+
+ /* Device 1 is connected and Device 2 is disconnected */
+ when(mHearingAidProfile.getConnectionStatus(mDevice1)).
+ thenReturn(BluetoothProfile.STATE_CONNECTED);
+ when(mHearingAidProfile.getConnectionStatus(mDevice2)).
+ thenReturn(BluetoothProfile.STATE_DISCONNECTED);
+
+ // Since both devices do not have hiSyncId, they should be added in mCachedDevices.
+ assertThat(mCachedDeviceManager.getCachedDevicesCopy()).hasSize(2);
+ assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).isEmpty();
+ assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).isEmpty();
+
+ cachedDevice1.setHiSyncId(HISYNCID1);
+ cachedDevice2.setHiSyncId(HISYNCID1);
+ mCachedDeviceManager.onHiSyncIdChanged(HISYNCID1);
+
+ // Only the connected device, device 1, should be visible to UI.
+ assertThat(mCachedDeviceManager.getCachedDevicesCopy()).containsExactly(cachedDevice1);
+ assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).
+ containsExactly(HISYNCID1, cachedDevice1);
+ assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).
+ containsExactly(cachedDevice2);
}
/**
* Test to verify onHiSyncIdChanged() for hearing aid devices with different HiSyncId.
*/
@Test
- public void testOnDeviceAdded_differentHiSyncId_populateInSameList() {
+ public void testOnHiSyncIdChanged_differentHiSyncId_populateInSameList() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
mLocalProfileManager, mDevice1);
assertThat(cachedDevice1).isNotNull();
@@ -303,6 +340,153 @@
}
/**
+ * Test to verify onProfileConnectionStateChanged() for single hearing aid device connection.
+ */
+ @Test
+ public void testOnProfileConnectionStateChanged_singleDeviceConnected_visible() {
+ CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
+ mLocalProfileManager, mDevice1);
+ assertThat(cachedDevice1).isNotNull();
+ cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+
+ // Since both devices do not have hiSyncId, they should be added in mCachedDevices.
+ assertThat(mCachedDeviceManager.getCachedDevicesCopy()).containsExactly(cachedDevice1);
+ assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).isEmpty();
+ assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).isEmpty();
+
+ cachedDevice1.setHiSyncId(HISYNCID1);
+ mCachedDeviceManager.onHiSyncIdChanged(HISYNCID1);
+
+ // Connect the Device 1
+ mCachedDeviceManager.onProfileConnectionStateChanged(cachedDevice1,
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
+
+ assertThat(mCachedDeviceManager.getCachedDevicesCopy()).containsExactly(cachedDevice1);
+ assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).
+ containsExactly(HISYNCID1, cachedDevice1);
+ assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).isEmpty();
+
+ // Disconnect the Device 1
+ mCachedDeviceManager.onProfileConnectionStateChanged(cachedDevice1,
+ BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.HEARING_AID);
+
+ assertThat(mCachedDeviceManager.getCachedDevicesCopy()).containsExactly(cachedDevice1);
+ assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).
+ containsExactly(HISYNCID1, cachedDevice1);
+ assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).isEmpty();
+ }
+
+ /**
+ * Test to verify onProfileConnectionStateChanged() for two hearing aid devices where both
+ * devices are disconnected and they get connected.
+ */
+ @Test
+ public void testOnProfileConnectionStateChanged_twoDevicesConnected_oneDeviceVisible() {
+ CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
+ mLocalProfileManager, mDevice1);
+ assertThat(cachedDevice1).isNotNull();
+ CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
+ mLocalProfileManager, mDevice2);
+ assertThat(cachedDevice2).isNotNull();
+ cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+ cachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+ when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+
+ // Since both devices do not have hiSyncId, they should be added in mCachedDevices.
+ assertThat(mCachedDeviceManager.getCachedDevicesCopy()).hasSize(2);
+ assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).isEmpty();
+ assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).isEmpty();
+
+ cachedDevice1.setHiSyncId(HISYNCID1);
+ cachedDevice2.setHiSyncId(HISYNCID1);
+ mCachedDeviceManager.onHiSyncIdChanged(HISYNCID1);
+
+ // There should be one cached device but can be either one.
+ assertThat(mCachedDeviceManager.getCachedDevicesCopy()).hasSize(1);
+
+ // Connect the Device 1
+ mCachedDeviceManager.onProfileConnectionStateChanged(cachedDevice1,
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
+
+ assertThat(mCachedDeviceManager.getCachedDevicesCopy()).containsExactly(cachedDevice1);
+ assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).
+ containsExactly(HISYNCID1, cachedDevice1);
+ assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).contains(cachedDevice2);
+ assertThat(mCachedDeviceManager.mCachedDevices).contains(cachedDevice1);
+
+ when(mHearingAidProfile.getConnectionStatus(mDevice1)).
+ thenReturn(BluetoothProfile.STATE_CONNECTED);
+ when(mHearingAidProfile.getConnectionStatus(mDevice2)).
+ thenReturn(BluetoothProfile.STATE_DISCONNECTED);
+
+ // Connect the Device 2
+ mCachedDeviceManager.onProfileConnectionStateChanged(cachedDevice2,
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
+
+ assertThat(mCachedDeviceManager.getCachedDevicesCopy()).hasSize(1);
+ assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).hasSize(1);
+ assertThat(mCachedDeviceManager.mCachedDevices).hasSize(1);
+ assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).hasSize(1);
+ }
+
+ /**
+ * Test to verify onProfileConnectionStateChanged() for two hearing aid devices where both
+ * devices are connected and they get disconnected.
+ */
+ @Test
+ public void testOnProfileConnectionStateChanged_twoDevicesDisconnected_oneDeviceVisible() {
+ CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
+ mLocalProfileManager, mDevice1);
+ assertThat(cachedDevice1).isNotNull();
+ CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
+ mLocalProfileManager, mDevice2);
+ assertThat(cachedDevice2).isNotNull();
+ cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+ cachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+
+ when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mHearingAidProfile.getConnectionStatus(mDevice1)).
+ thenReturn(BluetoothProfile.STATE_CONNECTED);
+ when(mHearingAidProfile.getConnectionStatus(mDevice2)).
+ thenReturn(BluetoothProfile.STATE_CONNECTED);
+
+ // Since both devices do not have hiSyncId, they should be added in mCachedDevices.
+ assertThat(mCachedDeviceManager.getCachedDevicesCopy()).hasSize(2);
+ assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).isEmpty();
+ assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).isEmpty();
+
+ cachedDevice1.setHiSyncId(HISYNCID1);
+ cachedDevice2.setHiSyncId(HISYNCID1);
+ mCachedDeviceManager.onHiSyncIdChanged(HISYNCID1);
+
+ /* Disconnect the Device 1 */
+ mCachedDeviceManager.onProfileConnectionStateChanged(cachedDevice1,
+ BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.HEARING_AID);
+
+ assertThat(mCachedDeviceManager.getCachedDevicesCopy()).containsExactly(cachedDevice2);
+ assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).contains(cachedDevice1);
+ assertThat(mCachedDeviceManager.mCachedDevices).contains(cachedDevice2);
+ assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids)
+ .containsExactly(HISYNCID1, cachedDevice2);
+
+ when(mHearingAidProfile.getConnectionStatus(mDevice1)).
+ thenReturn(BluetoothProfile.STATE_DISCONNECTED);
+ when(mHearingAidProfile.getConnectionStatus(mDevice2)).
+ thenReturn(BluetoothProfile.STATE_CONNECTED);
+
+ /* Disconnect the Device 2 */
+ mCachedDeviceManager.onProfileConnectionStateChanged(cachedDevice2,
+ BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.HEARING_AID);
+
+ assertThat(mCachedDeviceManager.getCachedDevicesCopy()).hasSize(1);
+ assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).hasSize(1);
+ assertThat(mCachedDeviceManager.mCachedDevices).hasSize(1);
+ assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).hasSize(1);
+ }
+
+ /**
* Test to verify OnDeviceUnpaired() for a paired hearing Aid device pair.
*/
@Test
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index db03ed2..dfa4bf9 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -28,7 +28,7 @@
android:clipToPadding="false"
android:orientation="vertical"
android:layout_centerHorizontal="true">
- <com.android.systemui.statusbar.AlphaOptimizedTextView
+ <view class="com.android.keyguard.KeyguardSliceView$TitleView"
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml
index 461d62e..6c1ae99 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml
@@ -29,7 +29,7 @@
</vector>
</aapt:attr>
- <!-- Repeat all animations 3 times but don't fade out at the end -->
+ <!-- Repeat all animations 5 times but don't fade out at the end -->
<target android:name="root">
<aapt:attr name="android:animation">
<set android:ordering="sequentially">
@@ -67,6 +67,34 @@
android:valueFrom="0"
android:valueTo="1"
android:interpolator="@android:anim/linear_interpolator" />
+ <!-- Linear fade out -->
+ <objectAnimator android:propertyName="alpha"
+ android:duration="100"
+ android:startOffset="1700"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:interpolator="@android:anim/linear_interpolator"/>
+ <!-- Linear fade in-->
+ <objectAnimator android:propertyName="alpha"
+ android:duration="100"
+ android:startOffset="100"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:interpolator="@android:anim/linear_interpolator" />
+ <!-- Linear fade out -->
+ <objectAnimator android:propertyName="alpha"
+ android:duration="100"
+ android:startOffset="1700"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:interpolator="@android:anim/linear_interpolator"/>
+ <!-- Linear fade in-->
+ <objectAnimator android:propertyName="alpha"
+ android:duration="100"
+ android:startOffset="100"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:interpolator="@android:anim/linear_interpolator" />
</set>
</aapt:attr>
</target>
@@ -117,6 +145,40 @@
<pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
+
+ <!-- Reset rotation position for fade in -->
+ <objectAnimator android:propertyName="rotation"
+ android:startOffset="1300"
+ android:duration="100"
+ android:valueFrom="?attr/rotateButtonStartAngle"
+ android:valueTo="?attr/rotateButtonStartAngle"/>
+
+ <!-- Icon rotation with start timing offset after fade in -->
+ <objectAnimator android:propertyName="rotation"
+ android:duration="600"
+ android:valueFrom="?attr/rotateButtonStartAngle"
+ android:valueTo="?attr/rotateButtonEndAngle">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+
+ <!-- Reset rotation position for fade in -->
+ <objectAnimator android:propertyName="rotation"
+ android:startOffset="1300"
+ android:duration="100"
+ android:valueFrom="?attr/rotateButtonStartAngle"
+ android:valueTo="?attr/rotateButtonStartAngle"/>
+
+ <!-- Icon rotation with start timing offset after fade in -->
+ <objectAnimator android:propertyName="rotation"
+ android:duration="600"
+ android:valueFrom="?attr/rotateButtonStartAngle"
+ android:valueTo="?attr/rotateButtonEndAngle">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.408,1.181 0.674,1.08 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
</set>
</aapt:attr>
</target>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index f066e34..f5abd06 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -47,6 +47,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.keyguard.KeyguardSliceProvider;
+import com.android.systemui.statusbar.AlphaOptimizedTextView;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
@@ -244,7 +245,7 @@
* @param charSequence Original text.
* @return Optimal string.
*/
- private CharSequence findBestLineBreak(CharSequence charSequence) {
+ private static CharSequence findBestLineBreak(CharSequence charSequence) {
if (TextUtils.isEmpty(charSequence)) {
return charSequence;
}
@@ -370,27 +371,6 @@
mIconSize = mContext.getResources().getDimensionPixelSize(R.dimen.widget_icon_size);
}
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- // Find best ellipsis strategy for the title.
- // Done on onMeasure since TextView#getLayout needs a measure pass to calculate its bounds.
- Layout layout = mTitle.getLayout();
- if (layout != null) {
- final int lineCount = layout.getLineCount();
- if (lineCount > 0) {
- if (layout.getEllipsisCount(lineCount - 1) == 0) {
- CharSequence title = mTitle.getText();
- CharSequence bestLineBreak = findBestLineBreak(title);
- if (!TextUtils.equals(title, bestLineBreak)) {
- mTitle.setText(bestLineBreak);
- }
- }
- }
- }
- }
-
public void refresh() {
Slice slice = SliceManager.getInstance(getContext()).bindSlice(mKeyguardSliceUri);
onChanged(slice);
@@ -553,6 +533,46 @@
}
}
+ /**
+ * A text view that will split its contents in 2 lines when possible.
+ */
+ static class TitleView extends AlphaOptimizedTextView {
+
+ public TitleView(Context context) {
+ super(context);
+ }
+
+ public TitleView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public TitleView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public TitleView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ Layout layout = getLayout();
+ int lineCount = layout.getLineCount();
+ boolean ellipsizing = layout.getEllipsisCount(lineCount - 1) != 0;
+ if (lineCount > 0 && !ellipsizing) {
+ CharSequence title = getText();
+ CharSequence bestLineBreak = findBestLineBreak(title);
+ if (!TextUtils.equals(title, bestLineBreak)) {
+ setText(bestLineBreak);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+ }
+ }
+
private class SliceViewTransitionListener implements LayoutTransition.TransitionListener {
@Override
public void startTransition(LayoutTransition transition, ViewGroup container, View view,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index e9d78d9..e2047bf 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -69,7 +69,7 @@
new DozeScreenState(wrappedService, handler, params, wakeLock),
createDozeScreenBrightness(context, wrappedService, sensorManager, host, params,
handler),
- new DozeWallpaperState(context, params)
+ new DozeWallpaperState(context)
});
return machine;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
index 9d110fb..47f86fe 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
@@ -38,40 +38,33 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final IWallpaperManager mWallpaperManagerService;
- private boolean mKeyguardVisible;
private boolean mIsAmbientMode;
private final DozeParameters mDozeParameters;
- public DozeWallpaperState(Context context, DozeParameters dozeParameters) {
+ public DozeWallpaperState(Context context) {
this(IWallpaperManager.Stub.asInterface(
ServiceManager.getService(Context.WALLPAPER_SERVICE)),
- dozeParameters, KeyguardUpdateMonitor.getInstance(context));
+ DozeParameters.getInstance(context));
}
@VisibleForTesting
- DozeWallpaperState(IWallpaperManager wallpaperManagerService, DozeParameters parameters,
- KeyguardUpdateMonitor keyguardUpdateMonitor) {
+ DozeWallpaperState(IWallpaperManager wallpaperManagerService, DozeParameters parameters) {
mWallpaperManagerService = wallpaperManagerService;
mDozeParameters = parameters;
- keyguardUpdateMonitor.registerCallback(new KeyguardUpdateMonitorCallback() {
- @Override
- public void onKeyguardVisibilityChanged(boolean showing) {
- mKeyguardVisible = showing;
- }
- });
}
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
final boolean isAmbientMode;
switch (newState) {
+ case DOZE:
case DOZE_AOD:
case DOZE_AOD_PAUSING:
case DOZE_AOD_PAUSED:
case DOZE_REQUEST_PULSE:
case DOZE_PULSING:
case DOZE_PULSE_DONE:
- isAmbientMode = mDozeParameters.getAlwaysOn();
+ isAmbientMode = true;
break;
default:
isAmbientMode = false;
@@ -81,7 +74,9 @@
if (isAmbientMode) {
animated = mDozeParameters.shouldControlScreenOff();
} else {
- animated = !mDozeParameters.getDisplayNeedsBlanking();
+ boolean wakingUpFromPulse = oldState == DozeMachine.State.DOZE_PULSING
+ && newState == DozeMachine.State.FINISH;
+ animated = !mDozeParameters.getDisplayNeedsBlanking() || wakingUpFromPulse;
}
if (isAmbientMode != mIsAmbientMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index ba265d8..d040f7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -18,13 +18,13 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.car.user.CarUserManagerHelper;
import android.content.Context;
import android.view.View;
import android.view.ViewStub;
import android.support.v7.widget.GridLayoutManager;
-import com.android.settingslib.users.UserManagerHelper;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -37,7 +37,7 @@
private final UserGridRecyclerView mUserGridView;
private final int mShortAnimDuration;
private final StatusBar mStatusBar;
- private final UserManagerHelper mUserManagerHelper;
+ private final CarUserManagerHelper mCarUserManagerHelper;
private int mCurrentForegroundUserId;
private boolean mShowing;
@@ -52,7 +52,7 @@
mUserGridView.buildAdapter();
mUserGridView.setUserSelectionListener(this::onUserSelected);
- mUserManagerHelper = new UserManagerHelper(context);
+ mCarUserManagerHelper = new CarUserManagerHelper(context);
updateCurrentForegroundUser();
mShortAnimDuration = mContainer.getResources()
@@ -84,11 +84,11 @@
}
private boolean foregroundUserChanged() {
- return mCurrentForegroundUserId != mUserManagerHelper.getForegroundUserId();
+ return mCurrentForegroundUserId != mCarUserManagerHelper.getCurrentForegroundUserId();
}
private void updateCurrentForegroundUser() {
- mCurrentForegroundUserId = mUserManagerHelper.getForegroundUserId();
+ mCurrentForegroundUserId = mCarUserManagerHelper.getCurrentForegroundUserId();
}
private void onUserSelected(UserGridRecyclerView.UserRecord record) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
index 68e47f7..dda25ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -21,6 +21,7 @@
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
+import android.car.user.CarUserManagerHelper;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.UserInfo;
@@ -41,7 +42,6 @@
import androidx.car.widget.PagedListView;
import com.android.internal.util.UserIcons;
-import com.android.settingslib.users.UserManagerHelper;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -53,16 +53,16 @@
* One of the uses of this is for the lock screen in auto.
*/
public class UserGridRecyclerView extends PagedListView implements
- UserManagerHelper.OnUsersUpdateListener {
+ CarUserManagerHelper.OnUsersUpdateListener {
private UserSelectionListener mUserSelectionListener;
private UserAdapter mAdapter;
- private UserManagerHelper mUserManagerHelper;
+ private CarUserManagerHelper mCarUserManagerHelper;
private Context mContext;
public UserGridRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
- mUserManagerHelper = new UserManagerHelper(mContext);
+ mCarUserManagerHelper = new CarUserManagerHelper(mContext);
}
/**
@@ -71,7 +71,7 @@
@Override
public void onFinishInflate() {
super.onFinishInflate();
- mUserManagerHelper.registerOnUsersUpdateListener(this);
+ mCarUserManagerHelper.registerOnUsersUpdateListener(this);
}
/**
@@ -80,7 +80,7 @@
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
- mUserManagerHelper.unregisterOnUsersUpdateListener();
+ mCarUserManagerHelper.unregisterOnUsersUpdateListener();
}
/**
@@ -89,7 +89,7 @@
* @return the adapter
*/
public void buildAdapter() {
- List<UserRecord> userRecords = createUserRecords(mUserManagerHelper
+ List<UserRecord> userRecords = createUserRecords(mCarUserManagerHelper
.getAllUsers());
mAdapter = new UserAdapter(mContext, userRecords);
super.setAdapter(mAdapter);
@@ -102,19 +102,20 @@
// Don't display guests in the switcher.
continue;
}
- boolean isForeground = mUserManagerHelper.getForegroundUserId() == userInfo.id;
+ boolean isForeground =
+ mCarUserManagerHelper.getCurrentForegroundUserId() == userInfo.id;
UserRecord record = new UserRecord(userInfo, false /* isStartGuestSession */,
false /* isAddUser */, isForeground);
userRecords.add(record);
}
// Add guest user record if the foreground user is not a guest
- if (!mUserManagerHelper.foregroundUserIsGuestUser()) {
+ if (!mCarUserManagerHelper.isForegroundUserGuest()) {
userRecords.add(addGuestUserRecord());
}
// Add add user record if the foreground user can add users
- if (mUserManagerHelper.foregroundUserCanAddUsers()) {
+ if (mCarUserManagerHelper.canForegroundUserAddUsers()) {
userRecords.add(addUserRecord());
}
@@ -148,7 +149,7 @@
@Override
public void onUsersUpdate() {
mAdapter.clearUsers();
- mAdapter.updateUsers(createUserRecords(mUserManagerHelper.getAllUsers()));
+ mAdapter.updateUsers(createUserRecords(mCarUserManagerHelper.getAllUsers()));
mAdapter.notifyDataSetChanged();
}
@@ -212,7 +213,7 @@
// If the user selects Guest, start the guest session.
if (userRecord.mIsStartGuestSession) {
- mUserManagerHelper.startNewGuestSession(mGuestName);
+ mCarUserManagerHelper.startNewGuestSession(mGuestName);
return;
}
@@ -239,14 +240,14 @@
return;
}
// If the user doesn't want to be a guest or add a user, switch to the user selected
- mUserManagerHelper.switchToUser(userRecord.mInfo);
+ mCarUserManagerHelper.switchToUser(userRecord.mInfo);
});
}
private Bitmap getUserRecordIcon(UserRecord userRecord) {
if (userRecord.mIsStartGuestSession) {
- return mUserManagerHelper.getGuestDefaultIcon();
+ return mCarUserManagerHelper.getGuestDefaultIcon();
}
if (userRecord.mIsAddUser) {
@@ -254,7 +255,7 @@
.getDrawable(R.drawable.car_add_circle_round));
}
- return mUserManagerHelper.getUserIcon(userRecord.mInfo);
+ return mCarUserManagerHelper.getUserIcon(userRecord.mInfo);
}
@Override
@@ -272,7 +273,10 @@
@Override
protected UserInfo doInBackground(String... userNames) {
- return mUserManagerHelper.createNewUser(userNames[0]);
+ // Default to create a non admin user for now. Need to add logic
+ // for user to choose whether they want to create an admin or non-admin
+ // user later.
+ return mCarUserManagerHelper.createNewNonAdminUser(userNames[0]);
}
@Override
@@ -282,7 +286,7 @@
@Override
protected void onPostExecute(UserInfo user) {
if (user != null) {
- mUserManagerHelper.switchToUser(user);
+ mCarUserManagerHelper.switchToUser(user);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 2a37845..68359bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -608,7 +608,7 @@
private int computeRotationProposalTimeout() {
if (mAccessibilityFeedbackEnabled) return 20000;
if (mHoveringRotationSuggestion) return 16000;
- return 6000;
+ return 10000;
}
private boolean isRotateSuggestionIntroduced() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
index 5c80bb5..6ac4462 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
@@ -45,13 +45,11 @@
private DozeWallpaperState mDozeWallpaperState;
@Mock IWallpaperManager mIWallpaperManager;
@Mock DozeParameters mDozeParameters;
- @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mDozeWallpaperState = new DozeWallpaperState(mIWallpaperManager, mDozeParameters,
- mKeyguardUpdateMonitor);
+ mDozeWallpaperState = new DozeWallpaperState(mIWallpaperManager, mDozeParameters);
}
@Test
@@ -100,4 +98,28 @@
mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_AOD, DozeMachine.State.FINISH);
verify(mIWallpaperManager).setInAmbientMode(eq(false), eq(false));
}
+
+ @Test
+ public void testTransitionTo_requestPulseIsAmbientMode() throws RemoteException {
+ mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE,
+ DozeMachine.State.DOZE_REQUEST_PULSE);
+ verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(false));
+ }
+
+ @Test
+ public void testTransitionTo_pulseIsAmbientMode() throws RemoteException {
+ mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_REQUEST_PULSE,
+ DozeMachine.State.DOZE_PULSING);
+ verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(false));
+ }
+
+ @Test
+ public void testTransitionTo_animatesWhenWakingUpFromPulse() throws RemoteException {
+ mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_REQUEST_PULSE,
+ DozeMachine.State.DOZE_PULSING);
+ reset(mIWallpaperManager);
+ mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_PULSING,
+ DozeMachine.State.FINISH);
+ verify(mIWallpaperManager).setInAmbientMode(eq(false), eq(true));
+ }
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 2a6f7c8..06329e57 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -1500,7 +1500,10 @@
userId = getUserOrWorkProfileId(clientPackage, userId);
if (userId != mCurrentUserId) {
int firstSdkInt = Build.VERSION.FIRST_SDK_INT;
- if (firstSdkInt == 0) firstSdkInt = Build.VERSION.SDK_INT;
+ if (firstSdkInt < Build.VERSION_CODES.BASE) {
+ Slog.e(TAG, "First SDK version " + firstSdkInt + " is invalid; must be " +
+ "at least VERSION_CODES.BASE");
+ }
File baseDir;
if (firstSdkInt <= Build.VERSION_CODES.O_MR1) {
baseDir = Environment.getUserSystemDirectory(userId);
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index b3aa0bf..442354b 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -235,6 +235,7 @@
* @param packageName The package that made the original volume request.
* @param pid The pid that made the original volume request.
* @param uid The uid that made the original volume request.
+ * @param caller caller binder. can be {@code null} if it's from the volume key.
* @param asSystemService {@code true} if the event sent to the session as if it was come from
* the system service instead of the app process. This helps sessions to distinguish
* between the key injection by the app and key events from the hardware devices.
@@ -244,8 +245,9 @@
* @param flags Any of the flags from {@link AudioManager}.
* @param useSuggested True to use adjustSuggestedStreamVolume instead of
*/
- public void adjustVolume(String packageName, int pid, int uid, boolean asSystemService,
- int direction, int flags, boolean useSuggested) {
+ public void adjustVolume(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, boolean asSystemService, int direction, int flags,
+ boolean useSuggested) {
int previousFlagPlaySound = flags & AudioManager.FLAG_PLAY_SOUND;
if (isPlaybackActive() || hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
flags &= ~AudioManager.FLAG_PLAY_SOUND;
@@ -266,7 +268,7 @@
Log.w(TAG, "Muting remote playback is not supported");
return;
}
- mSessionCb.adjustVolume(packageName, pid, uid, asSystemService, direction);
+ mSessionCb.adjustVolume(packageName, pid, uid, caller, asSystemService, direction);
int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
mOptimisticVolume = volumeBefore + direction;
@@ -285,7 +287,8 @@
}
}
- public void setVolumeTo(String packageName, int pid, int uid, int value, int flags) {
+ private void setVolumeTo(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, int value, int flags) {
if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
mAudioManagerInternal.setStreamVolumeForUid(stream, value, flags, packageName, uid);
@@ -295,7 +298,7 @@
return;
}
value = Math.max(0, Math.min(value, mMaxVolume));
- mSessionCb.setVolumeTo(packageName, pid, uid, value);
+ mSessionCb.setVolumeTo(packageName, pid, uid, caller, value);
int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
mOptimisticVolume = Math.max(0, Math.min(value, mMaxVolume));
@@ -611,6 +614,7 @@
try {
holder.mCallback.onVolumeInfoChanged(info);
} catch (DeadObjectException e) {
+ mControllerCallbackHolders.remove(i);
logCallbackException("Removing dead callback in pushVolumeUpdate", holder, e);
} catch (RemoteException e) {
logCallbackException("Unexpected exception in pushVolumeUpdate", holder, e);
@@ -629,8 +633,8 @@
try {
holder.mCallback.onEvent(event, data);
} catch (DeadObjectException e) {
- logCallbackException("Removing dead callback in pushEvent", holder, e);
mControllerCallbackHolders.remove(i);
+ logCallbackException("Removing dead callback in pushEvent", holder, e);
} catch (RemoteException e) {
logCallbackException("unexpected exception in pushEvent", holder, e);
}
@@ -705,14 +709,6 @@
return -1;
}
- private String getPackageName(int uid) {
- String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
- if (packages != null && packages.length > 0) {
- return packages[0];
- }
- return null;
- }
-
private final Runnable mClearOptimisticVolumeRunnable = new Runnable() {
@Override
public void run() {
@@ -913,14 +909,13 @@
public boolean sendMediaButton(String packageName, int pid, int uid,
boolean asSystemService, KeyEvent keyEvent, int sequenceId, ResultReceiver cb) {
- Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
- mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
try {
if (asSystemService) {
mCb.onMediaButton(mContext.getPackageName(), Process.myPid(),
- Process.SYSTEM_UID, mediaButtonIntent, sequenceId, cb);
+ Process.SYSTEM_UID, createMediaButtonIntent(keyEvent), sequenceId, cb);
} else {
- mCb.onMediaButton(packageName, pid, uid, mediaButtonIntent, sequenceId, cb);
+ mCb.onMediaButton(packageName, pid, uid,
+ createMediaButtonIntent(keyEvent), sequenceId, cb);
}
return true;
} catch (RemoteException e) {
@@ -929,205 +924,239 @@
return false;
}
- public void sendCommand(String packageName, int pid, int uid, String command, Bundle args,
- ResultReceiver cb) {
+ public boolean sendMediaButton(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, boolean asSystemService,
+ KeyEvent keyEvent) {
try {
- mCb.onCommand(packageName, pid, uid, command, args, cb);
+ if (asSystemService) {
+ mCb.onMediaButton(mContext.getPackageName(), Process.myPid(),
+ Process.SYSTEM_UID, createMediaButtonIntent(keyEvent), 0, null);
+ } else {
+ mCb.onMediaButtonFromController(packageName, pid, uid, caller,
+ createMediaButtonIntent(keyEvent));
+ }
+ return true;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
+ }
+ return false;
+ }
+
+ public void sendCommand(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, String command, Bundle args, ResultReceiver cb) {
+ try {
+ mCb.onCommand(packageName, pid, uid, caller, command, args, cb);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in sendCommand.", e);
}
}
- public void sendCustomAction(String packageName, int pid, int uid, String action,
+ public void sendCustomAction(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, String action,
Bundle args) {
try {
- mCb.onCustomAction(packageName, pid, uid, action, args);
+ mCb.onCustomAction(packageName, pid, uid, caller, action, args);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in sendCustomAction.", e);
}
}
- public void prepare(String packageName, int pid, int uid) {
+ public void prepare(String packageName, int pid, int uid,
+ ISessionControllerCallback caller) {
try {
- mCb.onPrepare(packageName, pid, uid);
+ mCb.onPrepare(packageName, pid, uid, caller);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in prepare.", e);
}
}
- public void prepareFromMediaId(String packageName, int pid, int uid, String mediaId,
- Bundle extras) {
+ public void prepareFromMediaId(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, String mediaId, Bundle extras) {
try {
- mCb.onPrepareFromMediaId(packageName, pid, uid, mediaId, extras);
+ mCb.onPrepareFromMediaId(packageName, pid, uid, caller, mediaId, extras);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in prepareFromMediaId.", e);
}
}
- public void prepareFromSearch(String packageName, int pid, int uid, String query,
- Bundle extras) {
+ public void prepareFromSearch(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, String query, Bundle extras) {
try {
- mCb.onPrepareFromSearch(packageName, pid, uid, query, extras);
+ mCb.onPrepareFromSearch(packageName, pid, uid, caller, query, extras);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in prepareFromSearch.", e);
}
}
- public void prepareFromUri(String packageName, int pid, int uid, Uri uri,
- Bundle extras) {
+ public void prepareFromUri(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, Uri uri, Bundle extras) {
try {
- mCb.onPrepareFromUri(packageName, pid, uid, uri, extras);
+ mCb.onPrepareFromUri(packageName, pid, uid, caller, uri, extras);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in prepareFromUri.", e);
}
}
- public void play(String packageName, int pid, int uid) {
+ public void play(String packageName, int pid, int uid, ISessionControllerCallback caller) {
try {
- mCb.onPlay(packageName, pid, uid);
+ mCb.onPlay(packageName, pid, uid, caller);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in play.", e);
}
}
- public void playFromMediaId(String packageName, int pid, int uid, String mediaId,
- Bundle extras) {
+ public void playFromMediaId(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, String mediaId, Bundle extras) {
try {
- mCb.onPlayFromMediaId(packageName, pid, uid, mediaId, extras);
+ mCb.onPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in playFromMediaId.", e);
}
}
- public void playFromSearch(String packageName, int pid, int uid, String query,
- Bundle extras) {
+ public void playFromSearch(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, String query, Bundle extras) {
try {
- mCb.onPlayFromSearch(packageName, pid, uid, query, extras);
+ mCb.onPlayFromSearch(packageName, pid, uid, caller, query, extras);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in playFromSearch.", e);
}
}
- public void playFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
+ public void playFromUri(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, Uri uri, Bundle extras) {
try {
- mCb.onPlayFromUri(packageName, pid, uid, uri, extras);
+ mCb.onPlayFromUri(packageName, pid, uid, caller, uri, extras);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in playFromUri.", e);
}
}
- public void skipToTrack(String packageName, int pid, int uid, long id) {
+ public void skipToTrack(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, long id) {
try {
- mCb.onSkipToTrack(packageName, pid, uid, id);
+ mCb.onSkipToTrack(packageName, pid, uid, caller, id);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in skipToTrack", e);
}
}
- public void pause(String packageName, int pid, int uid) {
+ public void pause(String packageName, int pid, int uid, ISessionControllerCallback caller) {
try {
- mCb.onPause(packageName, pid, uid);
+ mCb.onPause(packageName, pid, uid, caller);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in pause.", e);
}
}
- public void stop(String packageName, int pid, int uid) {
+ public void stop(String packageName, int pid, int uid, ISessionControllerCallback caller) {
try {
- mCb.onStop(packageName, pid, uid);
+ mCb.onStop(packageName, pid, uid, caller);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in stop.", e);
}
}
- public void next(String packageName, int pid, int uid) {
+ public void next(String packageName, int pid, int uid, ISessionControllerCallback caller) {
try {
- mCb.onNext(packageName, pid, uid);
+ mCb.onNext(packageName, pid, uid, caller);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in next.", e);
}
}
- public void previous(String packageName, int pid, int uid) {
+ public void previous(String packageName, int pid, int uid,
+ ISessionControllerCallback caller) {
try {
- mCb.onPrevious(packageName, pid, uid);
+ mCb.onPrevious(packageName, pid, uid, caller);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in previous.", e);
}
}
- public void fastForward(String packageName, int pid, int uid) {
+ public void fastForward(String packageName, int pid, int uid,
+ ISessionControllerCallback caller) {
try {
- mCb.onFastForward(packageName, pid, uid);
+ mCb.onFastForward(packageName, pid, uid, caller);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in fastForward.", e);
}
}
- public void rewind(String packageName, int pid, int uid) {
+ public void rewind(String packageName, int pid, int uid,
+ ISessionControllerCallback caller) {
try {
- mCb.onRewind(packageName, pid, uid);
+ mCb.onRewind(packageName, pid, uid, caller);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in rewind.", e);
}
}
- public void seekTo(String packageName, int pid, int uid, long pos) {
+ public void seekTo(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ long pos) {
try {
- mCb.onSeekTo(packageName, pid, uid, pos);
+ mCb.onSeekTo(packageName, pid, uid, caller, pos);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in seekTo.", e);
}
}
- public void rate(String packageName, int pid, int uid, Rating rating) {
+ public void rate(String packageName, int pid, int uid, ISessionControllerCallback caller,
+ Rating rating) {
try {
- mCb.onRate(packageName, pid, uid, rating);
+ mCb.onRate(packageName, pid, uid, caller, rating);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in rate.", e);
}
}
- public void adjustVolume(String packageName, int pid, int uid, boolean asSystemService,
- int direction) {
+ public void adjustVolume(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, boolean asSystemService, int direction) {
try {
if (asSystemService) {
mCb.onAdjustVolume(mContext.getPackageName(), Process.myPid(),
- Process.SYSTEM_UID, direction);
+ Process.SYSTEM_UID, null, direction);
} else {
- mCb.onAdjustVolume(packageName, pid, uid, direction);
+ mCb.onAdjustVolume(packageName, pid, uid, caller, direction);
}
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in adjustVolume.", e);
}
}
- public void setVolumeTo(String packageName, int pid, int uid, int value) {
+ public void setVolumeTo(String packageName, int pid, int uid,
+ ISessionControllerCallback caller, int value) {
try {
- mCb.onSetVolumeTo(packageName, pid, uid, value);
+ mCb.onSetVolumeTo(packageName, pid, uid, caller, value);
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in setVolumeTo.", e);
}
}
+
+ private Intent createMediaButtonIntent(KeyEvent keyEvent) {
+ Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ return mediaButtonIntent;
+ }
}
class ControllerStub extends ISessionController.Stub {
@Override
- public void sendCommand(String packageName, String command, Bundle args,
- ResultReceiver cb) {
+ public void sendCommand(String packageName, ISessionControllerCallback caller,
+ String command, Bundle args, ResultReceiver cb) {
mSessionCb.sendCommand(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
- command, args, cb);
+ caller, command, args, cb);
}
@Override
- public boolean sendMediaButton(String packageName, boolean asSystemService,
- KeyEvent mediaButtonIntent) {
+ public boolean sendMediaButton(String packageName, ISessionControllerCallback cb,
+ boolean asSystemService, KeyEvent keyEvent) {
return mSessionCb.sendMediaButton(packageName, Binder.getCallingPid(),
- Binder.getCallingUid(), asSystemService, mediaButtonIntent, 0, null);
+ Binder.getCallingUid(), cb, asSystemService, keyEvent);
}
@Override
- public void registerCallbackListener(ISessionControllerCallback cb) {
+ public void registerCallbackListener(String packageName, ISessionControllerCallback cb) {
synchronized (mLock) {
// If this session is already destroyed tell the caller and
// don't add them.
@@ -1141,24 +1170,24 @@
}
if (getControllerHolderIndexForCb(cb) < 0) {
mControllerCallbackHolders.add(new ISessionControllerCallbackHolder(cb,
- Binder.getCallingUid()));
+ packageName, Binder.getCallingUid()));
if (DEBUG) {
- Log.d(TAG, "registering controller callback " + cb);
+ Log.d(TAG, "registering controller callback " + cb + " from controller"
+ + packageName);
}
}
}
}
@Override
- public void unregisterCallbackListener(ISessionControllerCallback cb)
- throws RemoteException {
+ public void unregisterCallbackListener(ISessionControllerCallback cb) {
synchronized (mLock) {
int index = getControllerHolderIndexForCb(cb);
if (index != -1) {
mControllerCallbackHolders.remove(index);
}
if (DEBUG) {
- Log.d(TAG, "unregistering callback " + cb + ". index=" + index);
+ Log.d(TAG, "unregistering callback " + cb.asBinder());
}
}
}
@@ -1204,13 +1233,13 @@
}
@Override
- public void adjustVolume(String packageName, boolean asSystemService, int direction,
- int flags) {
+ public void adjustVolume(String packageName, ISessionControllerCallback caller,
+ boolean asSystemService, int direction, int flags) {
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
- MediaSessionRecord.this.adjustVolume(packageName, pid, uid, asSystemService,
+ MediaSessionRecord.this.adjustVolume(packageName, pid, uid, caller, asSystemService,
direction, flags, false /* useSuggested */);
} finally {
Binder.restoreCallingIdentity(token);
@@ -1218,115 +1247,128 @@
}
@Override
- public void setVolumeTo(String packageName, int value, int flags) {
+ public void setVolumeTo(String packageName, ISessionControllerCallback caller,
+ int value, int flags) {
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
- MediaSessionRecord.this.setVolumeTo(packageName, pid, uid, value, flags);
+ MediaSessionRecord.this.setVolumeTo(packageName, pid, uid, caller, value, flags);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
- public void prepare(String packageName) {
- mSessionCb.prepare(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+ public void prepare(String packageName, ISessionControllerCallback caller) {
+ mSessionCb.prepare(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
}
@Override
- public void prepareFromMediaId(String packageName, String mediaId, Bundle extras) {
+ public void prepareFromMediaId(String packageName, ISessionControllerCallback caller,
+ String mediaId, Bundle extras) {
mSessionCb.prepareFromMediaId(packageName, Binder.getCallingPid(),
- Binder.getCallingUid(), mediaId, extras);
+ Binder.getCallingUid(), caller, mediaId, extras);
}
@Override
- public void prepareFromSearch(String packageName, String query, Bundle extras) {
+ public void prepareFromSearch(String packageName, ISessionControllerCallback caller,
+ String query, Bundle extras) {
mSessionCb.prepareFromSearch(packageName, Binder.getCallingPid(),
- Binder.getCallingUid(), query, extras);
+ Binder.getCallingUid(), caller, query, extras);
}
@Override
- public void prepareFromUri(String packageName, Uri uri, Bundle extras) {
+ public void prepareFromUri(String packageName, ISessionControllerCallback caller,
+ Uri uri, Bundle extras) {
mSessionCb.prepareFromUri(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
- uri, extras);
+ caller, uri, extras);
}
@Override
- public void play(String packageName) {
- mSessionCb.play(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+ public void play(String packageName, ISessionControllerCallback caller) {
+ mSessionCb.play(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
}
@Override
- public void playFromMediaId(String packageName, String mediaId, Bundle extras) {
+ public void playFromMediaId(String packageName, ISessionControllerCallback caller,
+ String mediaId, Bundle extras) {
mSessionCb.playFromMediaId(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
- mediaId, extras);
+ caller, mediaId, extras);
}
@Override
- public void playFromSearch(String packageName, String query, Bundle extras) {
+ public void playFromSearch(String packageName, ISessionControllerCallback caller,
+ String query, Bundle extras) {
mSessionCb.playFromSearch(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
- query, extras);
+ caller, query, extras);
}
@Override
- public void playFromUri(String packageName, Uri uri, Bundle extras) {
+ public void playFromUri(String packageName, ISessionControllerCallback caller,
+ Uri uri, Bundle extras) {
mSessionCb.playFromUri(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
- uri, extras);
+ caller, uri, extras);
}
@Override
- public void skipToQueueItem(String packageName, long id) {
- mSessionCb.skipToTrack(packageName, Binder.getCallingPid(), Binder.getCallingUid(), id);
+ public void skipToQueueItem(String packageName, ISessionControllerCallback caller,
+ long id) {
+ mSessionCb.skipToTrack(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
+ caller, id);
}
@Override
- public void pause(String packageName) {
- mSessionCb.pause(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+ public void pause(String packageName, ISessionControllerCallback caller) {
+ mSessionCb.pause(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
}
@Override
- public void stop(String packageName) {
- mSessionCb.stop(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+ public void stop(String packageName, ISessionControllerCallback caller) {
+ mSessionCb.stop(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
}
@Override
- public void next(String packageName) {
- mSessionCb.next(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+ public void next(String packageName, ISessionControllerCallback caller) {
+ mSessionCb.next(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
}
@Override
- public void previous(String packageName) {
- mSessionCb.previous(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+ public void previous(String packageName, ISessionControllerCallback caller) {
+ mSessionCb.previous(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
+ caller);
}
@Override
- public void fastForward(String packageName) {
- mSessionCb.fastForward(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+ public void fastForward(String packageName, ISessionControllerCallback caller) {
+ mSessionCb.fastForward(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
+ caller);
}
@Override
- public void rewind(String packageName) {
- mSessionCb.rewind(packageName, Binder.getCallingPid(), Binder.getCallingUid());
+ public void rewind(String packageName, ISessionControllerCallback caller) {
+ mSessionCb.rewind(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller);
}
@Override
- public void seekTo(String packageName, long pos) {
- mSessionCb.seekTo(packageName, Binder.getCallingPid(), Binder.getCallingUid(), pos);
+ public void seekTo(String packageName, ISessionControllerCallback caller, long pos) {
+ mSessionCb.seekTo(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller,
+ pos);
}
@Override
- public void rate(String packageName, Rating rating) {
- mSessionCb.rate(packageName, Binder.getCallingPid(), Binder.getCallingUid(), rating);
+ public void rate(String packageName, ISessionControllerCallback caller, Rating rating) {
+ mSessionCb.rate(packageName, Binder.getCallingPid(), Binder.getCallingUid(), caller,
+ rating);
}
@Override
- public void sendCustomAction(String packageName, String action, Bundle args) {
+ public void sendCustomAction(String packageName, ISessionControllerCallback caller,
+ String action, Bundle args) {
mSessionCb.sendCustomAction(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
- action, args);
+ caller, action, args);
}
-
@Override
public MediaMetadata getMetadata() {
synchronized (mLock) {
@@ -1372,10 +1414,13 @@
private class ISessionControllerCallbackHolder {
private final ISessionControllerCallback mCallback;
private final String mPackageName;
+ private final int mUid;
- ISessionControllerCallbackHolder(ISessionControllerCallback callback, int uid) {
+ ISessionControllerCallbackHolder(ISessionControllerCallback callback, String packageName,
+ int uid) {
mCallback = callback;
- mPackageName = getPackageName(uid);
+ mPackageName = packageName;
+ mUid = uid;
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index a6e9389..6fff367 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -1851,7 +1851,7 @@
}
});
} else {
- session.adjustVolume(packageName, pid, uid, asSystemService,
+ session.adjustVolume(packageName, pid, uid, null, asSystemService,
direction, flags, true);
}
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 9ef6c66..492c6d6 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -184,6 +184,8 @@
private final PowerManager.WakeLock mWakeLock;
+ private final boolean mUseBpfTrafficStats;
+
private IConnectivityManager mConnManager;
@VisibleForTesting
@@ -347,6 +349,7 @@
mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers");
mSystemDir = checkNotNull(systemDir, "missing systemDir");
mBaseDir = checkNotNull(baseDir, "missing baseDir");
+ mUseBpfTrafficStats = new File("/sys/fs/bpf/traffic_uid_stats_map").exists();
LocalServices.addService(NetworkStatsManagerInternal.class,
new NetworkStatsManagerInternalImpl());
@@ -947,7 +950,7 @@
}
private boolean checkBpfStatsEnable() {
- return new File("/sys/fs/bpf/traffic_uid_stats_map").exists();
+ return mUseBpfTrafficStats;
}
/**
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 7f141ee..61b5415 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -25,22 +25,18 @@
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
-import android.content.pm.Signature;
import android.metrics.LogMaker;
import android.os.Build;
import android.os.UserHandle;
-import android.print.PrintManager;
import android.provider.Settings.Secure;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.RankingHelperProto;
import android.service.notification.RankingHelperProto.RecordProto;
import android.text.TextUtils;
import android.util.ArrayMap;
-import android.util.Pair;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
@@ -156,6 +152,8 @@
}
}
+ mAreChannelsBypassingDnd = (mZenModeHelper.getNotificationPolicy().state &
+ NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND) == 1;
updateChannelsBypassingDnd();
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2650ef0..f4853f3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -14090,13 +14090,9 @@
public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
PersistableBundle appExtras, PersistableBundle launcherExtras, String dialogMessage,
String callingPackage, int userId) {
- try {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS, null);
- } catch (SecurityException e) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_USERS,
- "Callers need to have either " + Manifest.permission.SUSPEND_APPS + " or "
- + Manifest.permission.MANAGE_USERS);
- }
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS,
+ "setPackagesSuspendedAsUser");
+
final int callingUid = Binder.getCallingUid();
if (callingUid != Process.ROOT_UID && callingUid != Process.SYSTEM_UID
&& getPackageUid(callingPackage, 0, userId) != callingUid) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
index 8905950..98c6ec4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -33,8 +33,10 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -115,7 +117,9 @@
@Mock PackageManager mPm;
@Mock IContentProvider mTestIContentProvider;
@Mock Context mContext;
+ @Mock ZenModeHelper mMockZenModeHelper;
+ private NotificationManager.Policy mTestNotificationPolicy;
private Notification mNotiGroupGSortA;
private Notification mNotiGroupGSortB;
private Notification mNotiNoGroup;
@@ -172,12 +176,12 @@
when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI)))
.thenReturn(SOUND_URI);
- ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
- mHelper = new RankingHelper(getContext(), mPm, mHandler, mockZenModeHelper,
+ mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
+ NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND);
+ when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
+ mHelper = new RankingHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
mUsageStats, new String[] {ImportanceExtractor.class.getName()});
-
- when(mockZenModeHelper.getNotificationPolicy()).thenReturn(new NotificationManager.Policy(
- 0, 0, 0));
+ resetZenModeHelper();
mNotiGroupGSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setContentTitle("A")
@@ -299,6 +303,11 @@
return null;
}
+ private void resetZenModeHelper() {
+ reset(mMockZenModeHelper);
+ when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
+ }
+
@Test
public void testFindAfterRankingWithASplitGroup() throws Exception {
ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3);
@@ -1136,44 +1145,86 @@
public void testCreateAndDeleteCanChannelsBypassDnd() throws Exception {
// create notification channel that can't bypass dnd
// expected result: areChannelsBypassingDnd = false
+ // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false
NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
mHelper.createNotificationChannel(PKG, UID, channel, true, false);
assertFalse(mHelper.areChannelsBypassingDnd());
+ verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
+ resetZenModeHelper();
- // create notification channel that can bypass dnd
+ // create notification channel that can bypass dnd
// expected result: areChannelsBypassingDnd = true
NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
channel2.setBypassDnd(true);
mHelper.createNotificationChannel(PKG, UID, channel2, true, true);
assertTrue(mHelper.areChannelsBypassingDnd());
+ verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
+ resetZenModeHelper();
// delete channels
mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND
+ verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
+ resetZenModeHelper();
+
mHelper.deleteNotificationChannel(PKG, UID, channel2.getId());
assertFalse(mHelper.areChannelsBypassingDnd());
-
+ verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
+ resetZenModeHelper();
}
@Test
public void testUpdateCanChannelsBypassDnd() throws Exception {
// create notification channel that can't bypass dnd
// expected result: areChannelsBypassingDnd = false
+ // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false
NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW);
mHelper.createNotificationChannel(PKG, UID, channel, true, false);
assertFalse(mHelper.areChannelsBypassingDnd());
+ verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
+ resetZenModeHelper();
// update channel so it CAN bypass dnd:
// expected result: areChannelsBypassingDnd = true
channel.setBypassDnd(true);
mHelper.updateNotificationChannel(PKG, UID, channel, true);
assertTrue(mHelper.areChannelsBypassingDnd());
+ verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
+ resetZenModeHelper();
// update channel so it can't bypass dnd:
// expected result: areChannelsBypassingDnd = false
channel.setBypassDnd(false);
mHelper.updateNotificationChannel(PKG, UID, channel, true);
assertFalse(mHelper.areChannelsBypassingDnd());
+ verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
+ resetZenModeHelper();
+ }
+
+ @Test
+ public void testSetupNewZenModeHelper_canBypass() {
+ // start notification policy off with mAreChannelsBypassingDnd = true, but
+ // RankingHelper should change to false
+ mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
+ NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND);
+ when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
+ mHelper = new RankingHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
+ mUsageStats, new String[] {ImportanceExtractor.class.getName()});
+ assertFalse(mHelper.areChannelsBypassingDnd());
+ verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
+ resetZenModeHelper();
+ }
+
+ @Test
+ public void testSetupNewZenModeHelper_cannotBypass() {
+ // start notification policy off with mAreChannelsBypassingDnd = false
+ mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 0);
+ when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
+ mHelper = new RankingHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
+ mUsageStats, new String[] {ImportanceExtractor.class.getName()});
+ assertFalse(mHelper.areChannelsBypassingDnd());
+ verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
+ resetZenModeHelper();
}
@Test