Merge "Initial code for listing/storing sound models"
diff --git a/api/current.txt b/api/current.txt
index 839e95d..95f6461 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3334,6 +3334,7 @@
method public void onAttachFragment(android.app.Fragment);
method public void onAttachedToWindow();
method public void onBackPressed();
+ method public void onBackgroundMediaPlayingChanged(boolean);
method protected void onChildTitleChanged(android.app.Activity, java.lang.CharSequence);
method public void onConfigurationChanged(android.content.res.Configuration);
method public void onContentChanged();
@@ -3389,6 +3390,7 @@
method public boolean onSearchRequested();
method protected void onStart();
method protected void onStop();
+ method public void onStopMediaPlaying();
method protected void onTitleChanged(java.lang.CharSequence, int);
method public boolean onTouchEvent(android.view.MotionEvent);
method public boolean onTrackballEvent(android.view.MotionEvent);
@@ -3423,6 +3425,7 @@
method public void setFinishOnTouchOutside(boolean);
method public void setImmersive(boolean);
method public void setIntent(android.content.Intent);
+ method public boolean setMediaPlaying(boolean);
method public final void setProgress(int);
method public final void setProgressBarIndeterminate(boolean);
method public final void setProgressBarIndeterminateVisibility(boolean);
@@ -27674,7 +27677,6 @@
}
public final class ConnectionRequest implements android.os.Parcelable {
- ctor public ConnectionRequest(android.net.Uri, android.os.Bundle);
ctor public ConnectionRequest(java.lang.String, android.net.Uri, android.os.Bundle);
ctor public ConnectionRequest(android.telecomm.PhoneAccount, java.lang.String, android.net.Uri, android.os.Bundle);
method public int describeContents();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 7934705..f1a2576 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -743,10 +743,13 @@
return Activity.this.findViewById(id);
}
};
-
+
+ // Most recent call to setMediaPlaying().
+ boolean mMediaPlaying;
+
ArrayMap<String, LoaderManagerImpl> mAllLoaderManagers;
LoaderManagerImpl mLoaderManager;
-
+
private static final class ManagedCursor {
ManagedCursor(Cursor cursor) {
mCursor = cursor;
@@ -764,6 +767,7 @@
// protected by synchronized (this)
int mResultCode = RESULT_CANCELED;
Intent mResultData = null;
+
private TranslucentConversionListener mTranslucentCallback;
private boolean mChangeCanvasToTranslucent;
@@ -5324,6 +5328,101 @@
}
/**
+ * Activities that want to show media behind a translucent activity above them must call this
+ * method anytime before a return from {@link #onPause()}. If this call is successful
+ * then the activity should continue to play media when {@link #onPause()} is called, but must
+ * stop playing and release resources prior to or within the call to
+ * {@link #onStopMediaPlaying()}. If this call returns false the activity must stop
+ * playing and release resources immediately.
+ *
+ * <p>Only fullscreen opaque activities may make this call. I.e. this call is a nop
+ * for dialog and translucent activities.
+ *
+ * <p>False will be returned any time this method is call between the return of onPause and
+ * the next call to onResume.
+ *
+ * @param playing true to notify the system that media is starting or continuing playing,
+ * false to indicate that media has stopped or is stopping. Resources must
+ * be released when passing false to this method.
+ * @return the resulting play state. If true the activity may continue playing media beyond
+ * {@link #onPause()}, if false then the caller must stop playing and immediately
+ * release all media resources. Returning false may occur in lieu of a call to
+ * onReleaseMediaResources() so the return value must be checked.
+ *
+ * @see #isBackgroundMediaPlaying()
+ * @see #onStopMediaPlaying()
+ * @see #onBackgroundMediaPlayingChanged(boolean)
+ */
+ public boolean setMediaPlaying(boolean playing) {
+ if (!mResumed) {
+ // Do not permit paused or stopped activities to start playing.
+ playing = false;
+ }
+ try {
+ mMediaPlaying = ActivityManagerNative.getDefault().setMediaPlaying(mToken, playing) &&
+ playing;
+ } catch (RemoteException e) {
+ mMediaPlaying = false;
+ }
+ return mMediaPlaying;
+ }
+
+ /**
+ * Called when a translucent activity over playing media is becoming opaque or another
+ * activity is being launched. Activities that call {@link #setMediaPlaying(boolean)}
+ * must implement this method to at the minimum call
+ * <code>super.onStopMediaPlayback()</code>.
+ *
+ * <p>When this method is called the activity has 500 msec to release the media resources.
+ * If the activity has not returned from this method in 500 msec the system will destroy
+ * the activity and kill the process in order to recover the media resources for another
+ * process. Otherwise {@link #onStop()} will be called following return.
+ *
+ * @see #setMediaPlaying(boolean)
+ * @see #isBackgroundMediaPlaying()
+ * @see #onBackgroundMediaPlayingChanged(boolean)
+ */
+ public void onStopMediaPlaying() {
+ mCalled = true;
+ }
+
+ /**
+ * Translucent activities may call this to determine if there is an activity below it that
+ * is playing media.
+ *
+ * @return true if media is playing according to the most recent call to
+ * {@link #setMediaPlaying(boolean)}, false otherwise.
+ *
+ * @see #setMediaPlaying(boolean)
+ * @see #onStopMediaPlaying()
+ * @see #onBackgroundMediaPlayingChanged(boolean)
+ * @hide
+ */
+ public boolean isBackgroundMediaPlaying() {
+ try {
+ return ActivityManagerNative.getDefault().isBackgroundMediaPlaying(mToken);
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
+
+ /**
+ * The topmost foreground activity will receive this call when an activity below it either
+ * starts or stops playing media.
+ *
+ * This call may be a consequence of {@link #setMediaPlaying(boolean)} or might be
+ * due to a background activity finishing itself.
+ *
+ * @param playing true if media playback is starting, false if it is stopping.
+ *
+ * @see #setMediaPlaying(boolean)
+ * @see #isBackgroundMediaPlaying()
+ * @see #onStopMediaPlaying()
+ */
+ public void onBackgroundMediaPlayingChanged(boolean playing) {
+ }
+
+ /**
* Adjust the current immersive mode setting.
*
* Note that changing this value will have no effect on the activity's
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index ce36fd8..4a70e15 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2176,6 +2176,33 @@
reply.writeNoException();
return true;
}
+
+ case SET_MEDIA_PLAYING_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ boolean enable = data.readInt() > 0;
+ boolean success = setMediaPlaying(token, enable);
+ reply.writeNoException();
+ reply.writeInt(success ? 1 : 0);
+ return true;
+ }
+
+ case IS_BG_MEDIA_PLAYING_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ final boolean enabled = isBackgroundMediaPlaying(token);
+ reply.writeNoException();
+ reply.writeInt(enabled ? 1 : 0);
+ return true;
+ }
+
+ case MEDIA_RESOURCES_RELEASED: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ mediaResourcesReleased(token);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -5007,5 +5034,46 @@
reply.recycle();
}
+ @Override
+ public boolean setMediaPlaying(IBinder token, boolean playing) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ data.writeInt(playing ? 1 : 0);
+ mRemote.transact(SET_MEDIA_PLAYING_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean success = reply.readInt() > 0;
+ data.recycle();
+ reply.recycle();
+ return success;
+ }
+
+ @Override
+ public boolean isBackgroundMediaPlaying(IBinder token) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(IS_BG_MEDIA_PLAYING_TRANSACTION, data, reply, 0);
+ reply.readException();
+ final boolean playing = reply.readInt() > 0;
+ data.recycle();
+ reply.recycle();
+ return playing;
+ }
+
+ @Override
+ public void mediaResourcesReleased(IBinder token) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(MEDIA_RESOURCES_RELEASED, data, reply, IBinder.FLAG_ONEWAY);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7b48e1d..184e10c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1153,6 +1153,16 @@
public final void updateTimePrefs(boolean is24Hour) {
DateFormat.set24HourTimePref(is24Hour);
}
+
+ @Override
+ public void scheduleStopMediaPlaying(IBinder token) {
+ sendMessage(H.STOP_MEDIA_PLAYING, token);
+ }
+
+ @Override
+ public void scheduleBackgroundMediaPlayingChanged(IBinder token, boolean playing) {
+ sendMessage(H.BACKGROUND_MEDIA_PLAYING_CHANGED, token, playing ? 1 : 0);
+ }
}
private class H extends Handler {
@@ -1203,6 +1213,8 @@
public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
public static final int INSTALL_PROVIDER = 145;
public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
+ public static final int STOP_MEDIA_PLAYING = 147;
+ public static final int BACKGROUND_MEDIA_PLAYING_CHANGED = 148;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
@@ -1253,6 +1265,8 @@
case TRANSLUCENT_CONVERSION_COMPLETE: return "TRANSLUCENT_CONVERSION_COMPLETE";
case INSTALL_PROVIDER: return "INSTALL_PROVIDER";
case ON_NEW_ACTIVITY_OPTIONS: return "ON_NEW_ACTIVITY_OPTIONS";
+ case STOP_MEDIA_PLAYING: return "STOP_MEDIA_PLAYING";
+ case BACKGROUND_MEDIA_PLAYING_CHANGED: return "BACKGROUND_MEDIA_PLAYING_CHANGED";
}
}
return Integer.toString(code);
@@ -1470,6 +1484,11 @@
case ON_NEW_ACTIVITY_OPTIONS:
Pair<IBinder, ActivityOptions> pair = (Pair<IBinder, ActivityOptions>) msg.obj;
onNewActivityOptions(pair.first, pair.second);
+ case STOP_MEDIA_PLAYING:
+ handleStopMediaPlaying((IBinder) msg.obj);
+ break;
+ case BACKGROUND_MEDIA_PLAYING_CHANGED:
+ handleOnBackgroundMediaPlayingChanged((IBinder) msg.obj, msg.arg1 > 0);
break;
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
@@ -2454,6 +2473,34 @@
}
}
+ public void handleStopMediaPlaying(IBinder token) {
+ ActivityClientRecord r = mActivities.get(token);
+ if (r != null) {
+ final Activity activity = r.activity;
+ if (activity.mMediaPlaying) {
+ activity.mCalled = false;
+ activity.onStopMediaPlaying();
+ // Tick, tick, tick. The activity has 500 msec to return or it will be destroyed.
+ if (!activity.mCalled) {
+ throw new SuperNotCalledException("Activity " + activity.getLocalClassName() +
+ " did not call through to super.onStopMediaPlayback()");
+ }
+ activity.mMediaPlaying = false;
+ }
+ }
+ try {
+ ActivityManagerNative.getDefault().mediaResourcesReleased(token);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public void handleOnBackgroundMediaPlayingChanged(IBinder token, boolean playing) {
+ ActivityClientRecord r = mActivities.get(token);
+ if (r != null) {
+ r.activity.onBackgroundMediaPlayingChanged(playing);
+ }
+ }
+
public void handleInstallProvider(ProviderInfo info) {
installContentProviders(mInitialApplication, Lists.newArrayList(info));
}
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 6c5c98b..1a03fe9 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -274,8 +274,8 @@
return names;
}
- public ArrayList<View> getMappedViews() {
- return mSharedElements;
+ public ArrayList<View> copyMappedViews() {
+ return new ArrayList<View>(mSharedElements);
}
public ArrayList<String> getAllSharedElementNames() { return mAllSharedElementNames; }
@@ -521,9 +521,7 @@
protected void clearState() {
// Clear the state so that we can't hold any references accidentally and leak memory.
mWindow = null;
- mAllSharedElementNames.clear();
mSharedElements.clear();
- mSharedElementNames.clear();
mTransitioningViews.clear();
mResultReceiver = null;
mPendingTransition = null;
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 0304246..0d2af8c 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -240,7 +240,7 @@
if (!mHasExited) {
mHasExited = true;
if (mEnterTransitionCoordinator != null) {
- mEnterTransitionCoordinator.stop();
+ mEnterTransitionCoordinator.cancelEnter();
mEnterTransitionCoordinator = null;
}
ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
@@ -268,7 +268,7 @@
if (mCalledExitCoordinator != null) {
mExitingFrom = mCalledExitCoordinator.getAcceptedNames();
mExitingTo = mCalledExitCoordinator.getMappedNames();
- mExitingToView = mCalledExitCoordinator.getMappedViews();
+ mExitingToView = mCalledExitCoordinator.copyMappedViews();
mCalledExitCoordinator.startExit();
}
}
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 6dead08..0b4510fe 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -647,6 +647,25 @@
reply.writeNoException();
return true;
}
+
+ case STOP_MEDIA_PLAYING_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ IBinder token = data.readStrongBinder();
+ scheduleStopMediaPlaying(token);
+ reply.writeNoException();
+ return true;
+ }
+
+ case BACKGROUND_MEDIA_PLAYING_CHANGED_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ IBinder token = data.readStrongBinder();
+ boolean enabled = data.readInt() > 0;
+ scheduleBackgroundMediaPlayingChanged(token, enabled);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -1304,4 +1323,23 @@
mRemote.transact(UPDATE_TIME_PREFS_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
data.recycle();
}
+
+ @Override
+ public void scheduleStopMediaPlaying(IBinder token) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(STOP_MEDIA_PLAYING_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
+
+ @Override
+ public void scheduleBackgroundMediaPlayingChanged(IBinder token, boolean enabled) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeStrongBinder(token);
+ data.writeInt(enabled ? 1 : 0);
+ mRemote.transact(BACKGROUND_MEDIA_PLAYING_CHANGED_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
}
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 5e18d0f..90f36b8 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -58,6 +58,7 @@
private Bundle mSharedElementsBundle;
private boolean mWasOpaque;
private boolean mAreViewsReady;
+ private boolean mIsViewsTransitionStarted;
public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
ArrayList<String> sharedElementNames, boolean isReturning) {
@@ -219,7 +220,7 @@
private void cancel() {
if (!mIsCanceled) {
mIsCanceled = true;
- if (getViewsTransition() == null) {
+ if (getViewsTransition() == null || mIsViewsTransitionStarted) {
setViewVisibility(mSharedElements, View.VISIBLE);
} else {
mTransitioningViews.addAll(mSharedElements);
@@ -363,6 +364,7 @@
stripOffscreenViews();
}
}
+ mIsViewsTransitionStarted = mIsViewsTransitionStarted || startEnterTransition;
Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
if (startSharedElementTransition) {
@@ -433,6 +435,17 @@
public void stop() {
makeOpaque();
+ mIsCanceled = true;
+ mResultReceiver = null;
+ if (mBackgroundAnimator != null) {
+ mBackgroundAnimator.end();
+ mBackgroundAnimator = null;
+ }
+ mActivity = null;
+ clearState();
+ }
+
+ public void cancelEnter() {
mHasStopped = true;
mIsCanceled = true;
mResultReceiver = null;
@@ -440,6 +453,8 @@
mBackgroundAnimator.cancel();
mBackgroundAnimator = null;
}
+ mActivity = null;
+ clearState();
}
private void makeOpaque() {
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 93cba0d..0fbd685 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -66,6 +66,8 @@
private Bundle mExitSharedElementBundle;
+ private boolean mIsExitStarted;
+
public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) {
super(activity.getWindow(), names, getListener(activity, isReturning),
@@ -114,6 +116,7 @@
setViewVisibility(mTransitioningViews, View.VISIBLE);
setViewVisibility(mSharedElements, View.VISIBLE);
mIsHidden = true;
+ clearState();
}
private void sharedElementExitBack() {
@@ -164,46 +167,52 @@
}
public void startExit() {
- startTransition(new Runnable() {
- @Override
- public void run() {
- beginTransitions();
- }
- });
- setViewVisibility(mTransitioningViews, View.INVISIBLE);
+ if (!mIsExitStarted) {
+ mIsExitStarted = true;
+ startTransition(new Runnable() {
+ @Override
+ public void run() {
+ beginTransitions();
+ }
+ });
+ setViewVisibility(mTransitioningViews, View.INVISIBLE);
+ }
}
public void startExit(int resultCode, Intent data) {
- mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- mIsCanceled = true;
- finish();
- }
- };
- mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
- if (getDecor().getBackground() == null) {
- ColorDrawable black = new ColorDrawable(0xFF000000);
- black.setAlpha(0);
- getWindow().setBackgroundDrawable(black);
- black.setAlpha(255);
- }
- ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
- mAllSharedElementNames, resultCode, data);
- mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
- @Override
- public void onTranslucentConversionComplete(boolean drawComplete) {
- if (!mIsCanceled) {
- fadeOutBackground();
+ if (!mIsExitStarted) {
+ mIsExitStarted = true;
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ mIsCanceled = true;
+ finish();
}
+ };
+ mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
+ if (getDecor().getBackground() == null) {
+ ColorDrawable black = new ColorDrawable(0xFF000000);
+ black.setAlpha(0);
+ getWindow().setBackgroundDrawable(black);
+ black.setAlpha(255);
}
- }, options);
- startTransition(new Runnable() {
- @Override
- public void run() {
- startExitTransition();
- }
- });
+ ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
+ mAllSharedElementNames, resultCode, data);
+ mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
+ @Override
+ public void onTranslucentConversionComplete(boolean drawComplete) {
+ if (!mIsCanceled) {
+ fadeOutBackground();
+ }
+ }
+ }, options);
+ startTransition(new Runnable() {
+ @Override
+ public void run() {
+ startExitTransition();
+ }
+ });
+ }
}
private void startExitTransition() {
@@ -216,20 +225,23 @@
private void fadeOutBackground() {
if (mBackgroundAnimator == null) {
- Drawable background = getDecor().getBackground();
- mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 0);
- mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mBackgroundAnimator = null;
- if (!mIsCanceled) {
- mIsBackgroundReady = true;
- notifyComplete();
+ ViewGroup decor = getDecor();
+ Drawable background;
+ if (decor != null && (background = decor.getBackground()) != null) {
+ mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 0);
+ mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBackgroundAnimator = null;
+ if (!mIsCanceled) {
+ mIsBackgroundReady = true;
+ notifyComplete();
+ }
}
- }
- });
- mBackgroundAnimator.setDuration(getFadeDuration());
- mBackgroundAnimator.start();
+ });
+ mBackgroundAnimator.setDuration(getFadeDuration());
+ mBackgroundAnimator.start();
+ }
}
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 6e4192b..b3a8a8a 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -415,11 +415,9 @@
public void performIdleMaintenance() throws RemoteException;
- /** @hide */
public IActivityContainer createActivityContainer(IBinder parentActivityToken,
IActivityContainerCallback callback) throws RemoteException;
- /** @hide */
public void deleteActivityContainer(IActivityContainer container) throws RemoteException;
public IActivityContainer getEnclosingActivityContainer(IBinder activityToken)
@@ -427,28 +425,25 @@
public IBinder getHomeActivityToken() throws RemoteException;
- /** @hide */
public void startLockTaskModeOnCurrent() throws RemoteException;
- /** @hide */
public void startLockTaskMode(int taskId) throws RemoteException;
- /** @hide */
public void startLockTaskMode(IBinder token) throws RemoteException;
- /** @hide */
public void stopLockTaskMode() throws RemoteException;
- /** @hide */
public void stopLockTaskModeOnCurrent() throws RemoteException;
- /** @hide */
public boolean isInLockTaskMode() throws RemoteException;
- /** @hide */
public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
throws RemoteException;
+ public boolean setMediaPlaying(IBinder token, boolean playing) throws RemoteException;
+ public boolean isBackgroundMediaPlaying(IBinder token) throws RemoteException;
+ public void mediaResourcesReleased(IBinder token) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -753,4 +748,7 @@
int STOP_LOCK_TASK_BY_CURRENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+222;
int FINISH_VOICE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+223;
int IS_TOP_OF_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+224;
+ int SET_MEDIA_PLAYING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+225;
+ int IS_BG_MEDIA_PLAYING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+226;
+ int MEDIA_RESOURCES_RELEASED = IBinder.FIRST_CALL_TRANSACTION+227;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index d3c4854..18faf0e 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -145,6 +145,8 @@
void setProcessState(int state) throws RemoteException;
void scheduleInstallProvider(ProviderInfo provider) throws RemoteException;
void updateTimePrefs(boolean is24Hour) throws RemoteException;
+ void scheduleStopMediaPlaying(IBinder token) throws RemoteException;
+ void scheduleBackgroundMediaPlayingChanged(IBinder token, boolean enabled) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -199,4 +201,6 @@
int SET_PROCESS_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+49;
int SCHEDULE_INSTALL_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+50;
int UPDATE_TIME_PREFS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+51;
+ int STOP_MEDIA_PLAYING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+52;
+ int BACKGROUND_MEDIA_PLAYING_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+53;
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index d75304f..35e5050 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -20,6 +20,7 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
@@ -37,6 +38,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
@@ -504,13 +506,7 @@
*/
public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
// TODO: Return null if this feature is not supported by hardware.
- try {
- IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
- return new BluetoothLeAdvertiser(iGatt);
- } catch (RemoteException e) {
- Log.e(TAG, "failed to get BluetoothLeAdvertiser, error: " + e);
- return null;
- }
+ return new BluetoothLeAdvertiser(mManagerService);
}
/**
@@ -518,13 +514,7 @@
*/
public BluetoothLeScanner getBluetoothLeScanner() {
// TODO: Return null if BLE scan is not supported by hardware.
- try {
- IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
- return new BluetoothLeScanner(iGatt);
- } catch (RemoteException e) {
- Log.e(TAG, "failed to get BluetoothLeScanner, error: " + e);
- return null;
- }
+ return new BluetoothLeScanner(mManagerService);
}
/**
@@ -2137,5 +2127,10 @@
public void onConnectionCongested(String address, boolean congested) {
// no op
}
+
+ @Override
+ public void onBatchScanResults(List<ScanResult> results) {
+ // no op
+ }
}
}
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 6c1a45e..4255cd4 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -16,6 +16,7 @@
package android.bluetooth;
+import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.os.ParcelUuid;
import android.os.RemoteException;
@@ -627,6 +628,11 @@
Log.w(TAG, "Unhandled exception in callback", ex);
}
}
+
+ @Override
+ public void onBatchScanResults(List<ScanResult> results) {
+ // no op
+ }
};
/*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device,
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 273d76d..5ed10a6 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -38,6 +38,7 @@
void startScanWithFilters(in int appIf, in boolean isServer,
in ScanSettings settings, in List<ScanFilter> filters);
void stopScan(in int appIf, in boolean isServer);
+ void flushPendingBatchResults(in int appIf, in boolean isServer);
void startMultiAdvertising(in int appIf,
in AdvertisementData advertiseData,
in AdvertisementData scanResponse,
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index 946a6f6..c18d357 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -16,7 +16,7 @@
package android.bluetooth;
import android.os.ParcelUuid;
-
+import android.bluetooth.le.ScanResult;
/**
* Callback definitions for interacting with BLE / GATT
@@ -27,6 +27,7 @@
void onClientConnectionState(in int status, in int clientIf,
in boolean connected, in String address);
void onScanResult(in String address, in int rssi, in byte[] advData);
+ void onBatchScanResults(in List<ScanResult> batchResults);
void onGetService(in String address, in int srvcType, in int srvcInstId,
in ParcelUuid srvcUuid);
void onGetIncludedService(in String address, in int srvcType, in int srvcInstId,
diff --git a/core/java/android/bluetooth/le/AdvertiseCallback.java b/core/java/android/bluetooth/le/AdvertiseCallback.java
index f1334c2..59f8cdc 100644
--- a/core/java/android/bluetooth/le/AdvertiseCallback.java
+++ b/core/java/android/bluetooth/le/AdvertiseCallback.java
@@ -52,6 +52,12 @@
public static final int ADVERTISE_FAILED_CONTROLLER_FAILURE = 5;
/**
+ * Operation fails due to GATT service failure.
+ * @hide
+ */
+ public static final int ADVERTISE_FAILED_GATT_SERVICE_FAILURE = 6;
+
+ /**
* Callback when advertising operation succeeds.
*
* @param settingsInEffect The actual settings used for advertising, which may be different from
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index c20b81b..a83d875 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -20,6 +20,7 @@
import android.bluetooth.BluetoothGatt;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothGattCallback;
+import android.bluetooth.IBluetoothManager;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
@@ -27,6 +28,7 @@
import android.util.Log;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -47,7 +49,7 @@
private static final String TAG = "BluetoothLeAdvertiser";
- private final IBluetoothGatt mBluetoothGatt;
+ private final IBluetoothManager mBluetoothManager;
private final Handler mHandler;
private final Map<AdvertiseCallback, AdvertiseCallbackWrapper>
mLeAdvertisers = new HashMap<AdvertiseCallback, AdvertiseCallbackWrapper>();
@@ -55,11 +57,11 @@
/**
* Use BluetoothAdapter.getLeAdvertiser() instead.
*
- * @param bluetoothGatt
+ * @param bluetoothManager
* @hide
*/
- public BluetoothLeAdvertiser(IBluetoothGatt bluetoothGatt) {
- mBluetoothGatt = bluetoothGatt;
+ public BluetoothLeAdvertiser(IBluetoothManager bluetoothManager) {
+ mBluetoothManager = bluetoothManager;
mHandler = new Handler(Looper.getMainLooper());
}
@@ -102,11 +104,19 @@
postCallbackFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED);
return;
}
+ IBluetoothGatt gatt;
+ try {
+ gatt = mBluetoothManager.getBluetoothGatt();
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to get bluetooth gatt - ", e);
+ postCallbackFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_CONTROLLER_FAILURE);
+ return;
+ }
AdvertiseCallbackWrapper wrapper = new AdvertiseCallbackWrapper(callback, advertiseData,
- scanResponse, settings, mBluetoothGatt);
+ scanResponse, settings, gatt);
UUID uuid = UUID.randomUUID();
try {
- mBluetoothGatt.registerClient(new ParcelUuid(uuid), wrapper);
+ gatt.registerClient(new ParcelUuid(uuid), wrapper);
if (wrapper.advertiseStarted()) {
mLeAdvertisers.put(callback, wrapper);
}
@@ -133,12 +143,19 @@
return;
}
try {
- mBluetoothGatt.stopMultiAdvertising(wrapper.mLeHandle);
+ IBluetoothGatt gatt = mBluetoothManager.getBluetoothGatt();
+ if (gatt == null) {
+ postCallbackFailure(callback,
+ AdvertiseCallback.ADVERTISE_FAILED_GATT_SERVICE_FAILURE);
+ }
+ gatt.stopMultiAdvertising(wrapper.mLeHandle);
if (wrapper.advertiseStopped()) {
mLeAdvertisers.remove(callback);
}
} catch (RemoteException e) {
Log.e(TAG, "failed to stop advertising", e);
+ postCallbackFailure(callback,
+ AdvertiseCallback.ADVERTISE_FAILED_GATT_SERVICE_FAILURE);
}
}
@@ -214,8 +231,6 @@
Log.e(TAG, "fail to start le advertise: " + e);
mLeHandle = -1;
notifyAll();
- } catch (Exception e) {
- Log.e(TAG, "fail to start advertise: " + e.getStackTrace());
}
} else {
// registration failed
@@ -360,6 +375,11 @@
public void onConnectionCongested(String address, boolean congested) {
// no op
}
+
+ @Override
+ public void onBatchScanResults(List<ScanResult> results) {
+ // no op
+ }
}
private void postCallbackFailure(final AdvertiseCallback callback, final int error) {
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index fbaf5d2..44aa117 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -21,6 +21,7 @@
import android.bluetooth.BluetoothGatt;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothGattCallback;
+import android.bluetooth.IBluetoothManager;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
@@ -51,15 +52,15 @@
private static final String TAG = "BluetoothLeScanner";
private static final boolean DBG = true;
- private final IBluetoothGatt mBluetoothGatt;
+ private final IBluetoothManager mBluetoothManager;
private final Handler mHandler;
private final Map<ScanCallback, BleScanCallbackWrapper> mLeScanClients;
/**
* @hide
*/
- public BluetoothLeScanner(IBluetoothGatt bluetoothGatt) {
- mBluetoothGatt = bluetoothGatt;
+ public BluetoothLeScanner(IBluetoothManager bluetoothManager) {
+ mBluetoothManager = bluetoothManager;
mHandler = new Handler(Looper.getMainLooper());
mLeScanClients = new HashMap<ScanCallback, BleScanCallbackWrapper>();
}
@@ -84,11 +85,21 @@
postCallbackError(callback, ScanCallback.SCAN_FAILED_ALREADY_STARTED);
return;
}
- BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(mBluetoothGatt, filters,
+ IBluetoothGatt gatt;
+ try {
+ gatt = mBluetoothManager.getBluetoothGatt();
+ } catch (RemoteException e) {
+ gatt = null;
+ }
+ if (gatt == null) {
+ postCallbackError(callback, ScanCallback.SCAN_FAILED_GATT_SERVICE_FAILURE);
+ return;
+ }
+ BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
settings, callback);
try {
UUID uuid = UUID.randomUUID();
- mBluetoothGatt.registerClient(new ParcelUuid(uuid), wrapper);
+ gatt.registerClient(new ParcelUuid(uuid), wrapper);
if (wrapper.scanStarted()) {
mLeScanClients.put(callback, wrapper);
} else {
@@ -131,18 +142,26 @@
}
/**
- * Poll scan results from bluetooth controller. This will return Bluetooth LE scan results
- * batched on bluetooth controller.
+ * Flush pending batch scan results stored in Bluetooth controller. This will return Bluetooth
+ * LE scan results batched on bluetooth controller. Returns immediately, batch scan results data
+ * will be delivered through the {@code callback}.
*
* @param callback Callback of the Bluetooth LE Scan, it has to be the same instance as the one
* used to start scan.
- * @param flush Whether to flush the batch scan buffer. Note the other batch scan clients will
- * get batch scan callback if the batch scan buffer is flushed.
- * @return Batch Scan results.
- * @hide TODO: unhide when batching is supported in stack.
+ *
+ * @hide
*/
- public List<ScanResult> getBatchScanResults(ScanCallback callback, boolean flush) {
- throw new UnsupportedOperationException("not impelemented");
+ public void flushPendingScanResults(ScanCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("callback cannot be null!");
+ }
+ synchronized (mLeScanClients) {
+ BleScanCallbackWrapper wrapper = mLeScanClients.get(callback);
+ if (wrapper == null) {
+ return;
+ }
+ wrapper.flushPendingBatchResults();
+ }
}
/**
@@ -195,13 +214,27 @@
mBluetoothGatt.stopScan(mLeHandle, false);
mBluetoothGatt.unregisterClient(mLeHandle);
} catch (RemoteException e) {
- Log.e(TAG, "Failed to stop scan and unregister" + e);
+ Log.e(TAG, "Failed to stop scan and unregister", e);
}
mLeHandle = -1;
notifyAll();
}
}
+ void flushPendingBatchResults() {
+ synchronized (this) {
+ if (mLeHandle <= 0) {
+ Log.e(TAG, "Error state, mLeHandle: " + mLeHandle);
+ return;
+ }
+ try {
+ mBluetoothGatt.flushPendingBatchResults(mLeHandle, false);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get pending scan results", e);
+ }
+ }
+ }
+
/**
* Application interface registered - app is ready to go
*/
@@ -256,9 +289,27 @@
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
address);
long scanNanos = SystemClock.elapsedRealtimeNanos();
- ScanResult result = new ScanResult(device, advData, rssi,
+ final ScanResult result = new ScanResult(device, advData, rssi,
scanNanos);
- mScanCallback.onAdvertisementUpdate(result);
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ mScanCallback.onAdvertisementUpdate(result);
+ }
+ });
+
+ }
+
+ @Override
+ public void onBatchScanResults(final List<ScanResult> results) {
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ mScanCallback.onBatchScanResults(results);
+ }
+ });
}
@Override
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 0a85675..3bb39b3 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -44,7 +44,6 @@
public static final int CALLBACK_TYPE_ON_UPDATE = 0;
/**
* Callback when a bluetooth advertisement is found for the first time.
- *
* @hide
*/
public static final int CALLBACK_TYPE_ON_FOUND = 1;
@@ -190,6 +189,7 @@
* {@link ScanSettings#SCAN_RESULT_TYPE_FULL} or
* {@link ScanSettings#SCAN_RESULT_TYPE_TRUNCATED}.
* @throws IllegalArgumentException If the {@code scanResultType} is invalid.
+ *
* @hide
*/
public Builder setScanResultType(int scanResultType) {
diff --git a/core/res/res/values-mcc214-mnc07/config.xml b/core/res/res/values-mcc214-mnc07/config.xml
new file mode 100644
index 0000000..ce7526c
--- /dev/null
+++ b/core/res/res/values-mcc214-mnc07/config.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
+ <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
+ <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
+ <integer-array translatable="false" name="config_tether_upstream_types">
+ <item>1</item>
+ <item>4</item>
+ <item>7</item>
+ <item>9</item>
+ </integer-array>
+
+ <!-- String containing the apn value for tethering. May be overriden by secure settings
+ TETHER_DUN_APN. Value is a comma separated series of strings:
+ "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
+ note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
+ <string translatable="false" name="config_tether_apndata">Conexion Compartida,movistar.es,,,MOVISTAR,MOVISTAR,,,,,214,07,1,DUN</string>
+
+</resources>
diff --git a/docs/html/preview/api-overview.jd b/docs/html/preview/api-overview.jd
index 2e99194..16bc444 100644
--- a/docs/html/preview/api-overview.jd
+++ b/docs/html/preview/api-overview.jd
@@ -781,7 +781,7 @@
$ rm /tmp/device_owner.xml
$ echo "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
>> /tmp/device_owner.xml
-$ echo "&device-owner package=\"<your_device_owner_package>\"
+$ echo "<device-owner package=\"<your_device_owner_package>\"
name=\"*<your_organization_name>\" />" >> /tmp/device_owner.xml
$ adb push /tmp/device_owner.xml /data/system/device_owner.xml
$ adb reboot
diff --git a/docs/html/tools/support-library/index.jd b/docs/html/tools/support-library/index.jd
index e905285..68eca49 100644
--- a/docs/html/tools/support-library/index.jd
+++ b/docs/html/tools/support-library/index.jd
@@ -61,6 +61,33 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" alt=""
+/>Android Support Library, revision 20</a> <em>(July 2014)</em>
+ </p>
+ <div class="toggle-content-toggleme">
+ <dl>
+ <dt>Changes for v4 support library:</dt>
+ <dd>
+ <ul>
+ <li>Added extended notification support for Android Wear in
+ {@link android.support.v4.app.NotificationCompat.WearableExtender}, which allows you
+ to specify wearable-specific features in your notifications.</li>
+ <li>Added {@link android.support.v4.app.NotificationCompat.Action.WearableExtender},
+ which allows actions to be added on wearable notifications.</li>
+ <li>Added {@link android.support.v4.app.NotificationManagerCompat}, which allows you
+ to issue notifications that properly support wearable features.</li>
+ <li>Added {@link android.support.v4.app.RemoteInput}, which allows a handheld device
+ to receive voice input from a notification that appears on a wearable device.</li>
+ <li>Improved the handling of touch feedback in
+ {@link android.support.v4.widget.SwipeRefreshLayout}.</li>
+ </ul>
+ </dd>
+ </dl>
+ </div>
+</div>
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
/>Android Support Library, revision 19.1.0</a> <em>(March 2014)</em>
</p>
<div class="toggle-content-toggleme">
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1da8123..dd7775d 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5608,7 +5608,22 @@
}
}
}
-
+
+ @Override
+ public final void mediaResourcesReleased(IBinder token) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ ActivityStack stack = ActivityRecord.getStackLocked(token);
+ if (stack != null) {
+ stack.mediaResourcesReleased(token);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
@Override
public String getCallingPackage(IBinder token) {
synchronized (this) {
@@ -9347,6 +9362,7 @@
}
if (r.changeWindowTranslucency(true)) {
mWindowManager.setAppFullscreen(token, true);
+ r.task.stack.releaseMediaResources();
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
return true;
}
@@ -9383,6 +9399,38 @@
}
@Override
+ public boolean setMediaPlaying(IBinder token, boolean playing) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r != null) {
+ return mStackSupervisor.setMediaPlayingLocked(r, playing);
+ }
+ }
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public boolean isBackgroundMediaPlaying(IBinder token) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final ActivityStack stack = ActivityRecord.getStackLocked(token);
+ final boolean playing = stack == null ? false : stack.isMediaPlaying();
+ if (ActivityStackSupervisor.DEBUG_MEDIA_VISIBILITY) Slog.d(TAG,
+ "isBackgroundMediaPlaying: stack=" + stack + " playing=" + playing);
+ return playing;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
public ActivityOptions getActivityOptions(IBinder token) {
final long origId = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index fd2a0b1..d70e8b7 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -203,6 +203,14 @@
pw.print(" resultWho="); pw.print(resultWho);
pw.print(" resultCode="); pw.println(requestCode);
}
+ if (taskDescription.getIcon() != null || taskDescription.getLabel() != null ||
+ taskDescription.getPrimaryColor() != 0) {
+ pw.print(prefix); pw.print("taskDescription:");
+ pw.print(" icon="); pw.print(taskDescription.getIcon());
+ pw.print(" label=\""); pw.print(taskDescription.getLabel()); pw.print("\"");
+ pw.print(" color=");
+ pw.println(Integer.toHexString(taskDescription.getPrimaryColor()));
+ }
if (results != null) {
pw.print(prefix); pw.print("results="); pw.println(results);
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ca518f3..c6bba22 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -32,7 +32,6 @@
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_APP;
@@ -47,6 +46,7 @@
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
+import com.android.server.am.ActivityStackSupervisor.ActivityDisplay;
import com.android.server.wm.AppTransition;
import com.android.server.wm.TaskGroup;
import com.android.server.wm.WindowManagerService;
@@ -252,14 +252,14 @@
static final int STOP_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 4;
static final int DESTROY_ACTIVITIES_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 5;
static final int TRANSLUCENT_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6;
+ static final int STOP_MEDIA_PLAYING_TIMEOUT_MSG =
+ ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 7;
static class ScheduleDestroyArgs {
final ProcessRecord mOwner;
- final boolean mOomAdj;
final String mReason;
- ScheduleDestroyArgs(ProcessRecord owner, boolean oomAdj, String reason) {
+ ScheduleDestroyArgs(ProcessRecord owner, String reason) {
mOwner = owner;
- mOomAdj = oomAdj;
mReason = reason;
}
}
@@ -320,7 +320,7 @@
case DESTROY_ACTIVITIES_MSG: {
ScheduleDestroyArgs args = (ScheduleDestroyArgs)msg.obj;
synchronized (mService) {
- destroyActivitiesLocked(args.mOwner, args.mOomAdj, args.mReason);
+ destroyActivitiesLocked(args.mOwner, args.mReason);
}
} break;
case TRANSLUCENT_TIMEOUT_MSG: {
@@ -328,6 +328,15 @@
notifyActivityDrawnLocked(null);
}
} break;
+ case STOP_MEDIA_PLAYING_TIMEOUT_MSG: {
+ synchronized (mService) {
+ final ActivityRecord r = getMediaPlayer();
+ Slog.e(TAG, "Timeout waiting for stopMediaPlaying player=" + r);
+ if (r != null) {
+ mService.killAppAtUsersRequest(r.app, null);
+ }
+ }
+ } break;
}
}
}
@@ -930,11 +939,14 @@
mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
r.stopped = true;
r.state = ActivityState.STOPPED;
+ if (mActivityContainer.mActivityDisplay.mMediaPlayingActivity == r) {
+ mStackSupervisor.setMediaPlayingLocked(r, false);
+ }
if (r.finishing) {
r.clearOptionsLocked();
} else {
if (r.configDestroy) {
- destroyActivityLocked(r, true, false, "stop-config");
+ destroyActivityLocked(r, true, "stop-config");
mStackSupervisor.resumeTopActivitiesLocked();
} else {
mStackSupervisor.updatePreviousProcessLocked(r);
@@ -966,8 +978,10 @@
// instance right now, we need to first completely stop
// the current instance before starting the new one.
if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
- destroyActivityLocked(prev, true, false, "pause-config");
- } else {
+ destroyActivityLocked(prev, true, "pause-config");
+ } else if (!isMediaPlaying()) {
+ // If we were playing then resumeTopActivities will release resources before
+ // stopping.
mStackSupervisor.mStoppingActivities.add(prev);
if (mStackSupervisor.mStoppingActivities.size() > 3 ||
prev.frontOfTask && mTaskHistory.size() <= 1) {
@@ -1280,10 +1294,14 @@
case PAUSED:
// This case created for transitioning activities from
// translucent to opaque {@link Activity#convertToOpaque}.
- if (!mStackSupervisor.mStoppingActivities.contains(r)) {
- mStackSupervisor.mStoppingActivities.add(r);
+ if (getMediaPlayer() == r) {
+ releaseMediaResources();
+ } else {
+ if (!mStackSupervisor.mStoppingActivities.contains(r)) {
+ mStackSupervisor.mStoppingActivities.add(r);
+ }
+ mStackSupervisor.scheduleIdleLocked();
}
- mStackSupervisor.scheduleIdleLocked();
break;
default:
@@ -1548,8 +1566,6 @@
// very soon and it would be a waste to let it get killed if it
// happens to be sitting towards the end.
if (next.app != null && next.app.thread != null) {
- // No reason to do full oom adj update here; we'll let that
- // happen whenever it needs to later.
mService.updateLruProcessLocked(next.app, true, null);
}
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2433,7 +2449,7 @@
if (DEBUG_STATES) Slog.v(TAG, "Stop failed; moving to STOPPED: " + r);
r.state = ActivityState.STOPPED;
if (r.configDestroy) {
- destroyActivityLocked(r, true, false, "stop-except");
+ destroyActivityLocked(r, true, "stop-except");
}
}
}
@@ -2693,7 +2709,7 @@
// If this activity is already stopped, we can just finish
// it right now.
r.makeFinishing();
- boolean activityRemoved = destroyActivityLocked(r, true, oomAdj, "finish-imm");
+ boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");
if (activityRemoved) {
mStackSupervisor.resumeTopActivitiesLocked();
}
@@ -2856,6 +2872,9 @@
// Get rid of any pending idle timeouts.
removeTimeoutsForActivityLocked(r);
+ if (getMediaPlayer() == r) {
+ mStackSupervisor.setMediaPlayingLocked(r, false);
+ }
}
private void removeTimeoutsForActivityLocked(ActivityRecord r) {
@@ -2914,13 +2933,13 @@
}
}
- final void scheduleDestroyActivities(ProcessRecord owner, boolean oomAdj, String reason) {
+ final void scheduleDestroyActivities(ProcessRecord owner, String reason) {
Message msg = mHandler.obtainMessage(DESTROY_ACTIVITIES_MSG);
- msg.obj = new ScheduleDestroyArgs(owner, oomAdj, reason);
+ msg.obj = new ScheduleDestroyArgs(owner, reason);
mHandler.sendMessage(msg);
}
- final void destroyActivitiesLocked(ProcessRecord owner, boolean oomAdj, String reason) {
+ final void destroyActivitiesLocked(ProcessRecord owner, String reason) {
boolean lastIsOpaque = false;
boolean activityRemoved = false;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -2948,7 +2967,7 @@
if (DEBUG_SWITCH) Slog.v(TAG, "Destroying " + r + " in state " + r.state
+ " resumed=" + mResumedActivity
+ " pausing=" + mPausingActivity);
- if (destroyActivityLocked(r, true, oomAdj, reason)) {
+ if (destroyActivityLocked(r, true, reason)) {
activityRemoved = true;
}
}
@@ -2965,8 +2984,7 @@
* a configuration switch where we destroy the current client-side object
* but then create a new client-side object for this same HistoryRecord.
*/
- final boolean destroyActivityLocked(ActivityRecord r,
- boolean removeFromApp, boolean oomAdj, String reason) {
+ final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) {
if (DEBUG_SWITCH || DEBUG_CLEANUP) Slog.v(
TAG, "Removing activity from " + reason + ": token=" + r
+ ", app=" + (r.app != null ? r.app.processName : "(null)"));
@@ -3077,6 +3095,49 @@
}
}
+ void releaseMediaResources() {
+ if (isMediaPlaying() && !mHandler.hasMessages(STOP_MEDIA_PLAYING_TIMEOUT_MSG)) {
+ final ActivityRecord r = getMediaPlayer();
+ if (DEBUG_STATES) Slog.d(TAG, "releaseMediaResources activtyDisplay=" +
+ mActivityContainer.mActivityDisplay + " mediaPlayer=" + r + " app=" + r.app +
+ " thread=" + r.app.thread);
+ if (r != null && r.app != null && r.app.thread != null) {
+ try {
+ r.app.thread.scheduleStopMediaPlaying(r.appToken);
+ } catch (RemoteException e) {
+ }
+ mHandler.sendEmptyMessageDelayed(STOP_MEDIA_PLAYING_TIMEOUT_MSG, 500);
+ } else {
+ Slog.e(TAG, "releaseMediaResources: activity " + r + " no longer running");
+ mediaResourcesReleased(r.appToken);
+ }
+ }
+ }
+
+ final void mediaResourcesReleased(IBinder token) {
+ mHandler.removeMessages(STOP_MEDIA_PLAYING_TIMEOUT_MSG);
+ final ActivityRecord r = getMediaPlayer();
+ if (r != null) {
+ mStackSupervisor.mStoppingActivities.add(r);
+ setMediaPlayer(null);
+ }
+ mStackSupervisor.resumeTopActivitiesLocked();
+ }
+
+ boolean isMediaPlaying() {
+ return isAttached() && mActivityContainer.mActivityDisplay.isMediaPlaying();
+ }
+
+ void setMediaPlayer(ActivityRecord r) {
+ if (isAttached()) {
+ mActivityContainer.mActivityDisplay.setMediaPlaying(r);
+ }
+ }
+
+ ActivityRecord getMediaPlayer() {
+ return isAttached() ? mActivityContainer.mActivityDisplay.mMediaPlayingActivity : null;
+ }
+
private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
ProcessRecord app, String listName) {
int i = list.size();
@@ -3448,7 +3509,7 @@
if (r.app == null || r.app.thread == null) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
"Config is destroying non-running " + r);
- destroyActivityLocked(r, true, false, "config");
+ destroyActivityLocked(r, true, "config");
} else if (r.state == ActivityState.PAUSING) {
// A little annoying: we are waiting for this activity to
// finish pausing. Let's not do anything now, but just
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c4423de..65afd71 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -49,7 +49,6 @@
import android.app.IActivityManager.WaitResult;
import android.app.ResultInfo;
import android.app.StatusBarManager;
-import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
@@ -116,6 +115,7 @@
static final boolean DEBUG_APP = DEBUG || false;
static final boolean DEBUG_CONTAINERS = DEBUG || false;
static final boolean DEBUG_IDLE = DEBUG || false;
+ static final boolean DEBUG_MEDIA_VISIBILITY = DEBUG || false;
static final boolean DEBUG_SAVED_STATE = DEBUG || false;
static final boolean DEBUG_SCREENSHOTS = DEBUG || false;
static final boolean DEBUG_STATES = DEBUG || false;
@@ -2102,7 +2102,7 @@
// waiting for the next one to start.
for (int i = 0; i < NF; i++) {
r = finishes.get(i);
- activityRemoved |= r.task.stack.destroyActivityLocked(r, true, false, "finish-idle");
+ activityRemoved |= r.task.stack.destroyActivityLocked(r, true, "finish-idle");
}
if (booting) {
@@ -2298,6 +2298,14 @@
}
IBinder getHomeActivityToken() {
+ ActivityRecord homeActivity = getHomeActivity();
+ if (homeActivity != null) {
+ return homeActivity.appToken;
+ }
+ return null;
+ }
+
+ ActivityRecord getHomeActivity() {
final ArrayList<TaskRecord> tasks = mHomeStack.getAllTasks();
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = tasks.get(taskNdx);
@@ -2306,7 +2314,7 @@
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
if (r.isHomeActivity()) {
- return r.appToken;
+ return r;
}
}
}
@@ -2594,6 +2602,42 @@
}
}
+ boolean setMediaPlayingLocked(ActivityRecord r, boolean playing) {
+ final ActivityStack stack = r.task.stack;
+ if (stack == null) {
+ if (DEBUG_MEDIA_VISIBILITY) Slog.d(TAG, "setMediaPlaying: r=" + r + " playing=" +
+ playing + " stack is null");
+ return false;
+ }
+ final boolean isPlaying = stack.isMediaPlaying();
+ if (DEBUG_MEDIA_VISIBILITY) Slog.d(TAG, "setMediaPlayer: r=" + r + " playing=" +
+ playing + " isPlaying=" + isPlaying);
+
+ final ActivityRecord top = topRunningActivityLocked();
+ if (top == null || top == r || (playing == isPlaying)) {
+ if (DEBUG_MEDIA_VISIBILITY) Slog.d(TAG, "setMediaPlaying: quick return");
+ stack.setMediaPlayer(playing ? r : null);
+ return true;
+ }
+
+ // A non-top activity is reporting a visibility change.
+ if (top.fullscreen || top.state != ActivityState.RESUMED || top.app == null ||
+ top.app.thread == null) {
+ // Can't carry out this request.
+ if (DEBUG_MEDIA_VISIBILITY) Slog.d(TAG, "setMediaPlaying: returning top.fullscreen=" +
+ top.fullscreen+ " top.state=" + top.state + " top.app=" + top.app +
+ " top.app.thread=" + top.app.thread);
+ return false;
+ }
+
+ stack.setMediaPlayer(playing ? r : null);
+ try {
+ top.app.thread.scheduleBackgroundMediaPlayingChanged(top.appToken, playing);
+ } catch (RemoteException e) {
+ }
+ return true;
+ }
+
void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
// First the front stacks. In case any are not fullscreen and are in front of home.
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
@@ -2612,7 +2656,7 @@
final int numStacks = stacks.size();
for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
- stack.scheduleDestroyActivities(app, false, reason);
+ stack.scheduleDestroyActivities(app, reason);
}
}
}
@@ -2774,7 +2818,8 @@
boolean needSep = false;
for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx);
- pw.print("Display #"); pw.println(activityDisplay.mDisplayId);
+ pw.print("Display #"); pw.print(activityDisplay.mDisplayId);
+ pw.println(" (activities from bottom to top):");
ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
final int numStacks = stacks.size();
for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
@@ -3584,6 +3629,8 @@
* stacks, bottommost behind. Accessed directly by ActivityManager package classes */
final ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
+ ActivityRecord mMediaPlayingActivity;
+
ActivityDisplay() {
}
@@ -3615,6 +3662,14 @@
bounds.y = mDisplayInfo.appHeight;
}
+ void setMediaPlaying(ActivityRecord r) {
+ mMediaPlayingActivity = r;
+ }
+
+ boolean isMediaPlaying() {
+ return mMediaPlayingActivity != null;
+ }
+
@Override
public String toString() {
return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 6b60ea4..0e6265c 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -25,6 +25,7 @@
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.util.Arrays;
+import java.util.Objects;
/**
* Holds data about notifications that should not be shared with the
@@ -201,6 +202,10 @@
return mIntercept;
}
+ public boolean isCategory(String category) {
+ return Objects.equals(category, getNotification().category);
+ }
+
/**
* Returns the timestamp to use for time-based sorting in the ranker.
*/
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 92bec14..f74e371 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -21,6 +21,7 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -34,6 +35,7 @@
import android.os.IBinder;
import android.provider.Settings.Global;
import android.service.notification.ZenModeConfig;
+import android.telecomm.TelecommManager;
import android.util.Slog;
import com.android.internal.R;
@@ -72,17 +74,13 @@
private final ZenModeConfig mDefaultConfig;
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+ private ComponentName mDefaultPhoneApp;
private int mZenMode;
private ZenModeConfig mConfig;
private AudioManager mAudioManager;
private int mPreviousRingerMode = -1;
// temporary, until we update apps to provide metadata
- private static final Set<String> CALL_PACKAGES = new HashSet<String>(Arrays.asList(
- "com.google.android.dialer",
- "com.android.phone",
- "com.android.example.notificationshowcase"
- ));
private static final Set<String> MESSAGE_PACKAGES = new HashSet<String>(Arrays.asList(
"com.google.android.talk",
"com.android.mms",
@@ -224,7 +222,7 @@
public boolean allowDisable(int what, IBinder token, String pkg) {
// TODO(cwren): delete this API before the next release. Bug:15344099
- if (CALL_PACKAGES.contains(pkg)) {
+ if (isDefaultPhoneApp(pkg)) {
return mZenMode == Global.ZEN_MODE_OFF || mConfig.allowCalls;
}
return true;
@@ -236,6 +234,7 @@
pw.print(prefix); pw.print("mConfig="); pw.println(mConfig);
pw.print(prefix); pw.print("mDefaultConfig="); pw.println(mDefaultConfig);
pw.print(prefix); pw.print("mPreviousRingerMode="); pw.println(mPreviousRingerMode);
+ pw.print(prefix); pw.print("mDefaultPhoneApp="); pw.println(mDefaultPhoneApp);
}
public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException {
@@ -280,7 +279,7 @@
private boolean isSystem(NotificationRecord record) {
return SYSTEM_PACKAGES.contains(record.sbn.getPackageName())
- && Notification.CATEGORY_SYSTEM.equals(record.getNotification().category);
+ && record.isCategory(Notification.CATEGORY_SYSTEM);
}
private boolean isAlarm(NotificationRecord record) {
@@ -288,7 +287,19 @@
}
private boolean isCall(NotificationRecord record) {
- return CALL_PACKAGES.contains(record.sbn.getPackageName());
+ return isDefaultPhoneApp(record.sbn.getPackageName())
+ || record.isCategory(Notification.CATEGORY_CALL);
+ }
+
+ private boolean isDefaultPhoneApp(String pkg) {
+ if (mDefaultPhoneApp == null) {
+ final TelecommManager telecomm =
+ (TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
+ mDefaultPhoneApp = telecomm != null ? telecomm.getDefaultPhoneApp() : null;
+ Slog.d(TAG, "Default phone app: " + mDefaultPhoneApp);
+ }
+ return pkg != null && mDefaultPhoneApp != null
+ && pkg.equals(mDefaultPhoneApp.getPackageName());
}
private boolean isMessage(NotificationRecord record) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 194e85d..64288a5 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -394,16 +394,21 @@
@Override
public void setUserIcon(int userId, Bitmap bitmap) {
checkManageUsersPermission("update users");
- synchronized (mPackagesLock) {
- UserInfo info = mUsers.get(userId);
- if (info == null || info.partial) {
- Slog.w(LOG_TAG, "setUserIcon: unknown user #" + userId);
- return;
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mPackagesLock) {
+ UserInfo info = mUsers.get(userId);
+ if (info == null || info.partial) {
+ Slog.w(LOG_TAG, "setUserIcon: unknown user #" + userId);
+ return;
+ }
+ writeBitmapLocked(info, bitmap);
+ writeUserLocked(info);
}
- writeBitmapLocked(info, bitmap);
- writeUserLocked(info);
+ sendUserInfoChangedBroadcast(userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- sendUserInfoChangedBroadcast(userId);
}
private void sendUserInfoChangedBroadcast(int userId) {
diff --git a/telecomm/java/android/telecomm/ConnectionRequest.java b/telecomm/java/android/telecomm/ConnectionRequest.java
index ed61622..939ac8d 100644
--- a/telecomm/java/android/telecomm/ConnectionRequest.java
+++ b/telecomm/java/android/telecomm/ConnectionRequest.java
@@ -35,10 +35,6 @@
private final Bundle mExtras;
private final PhoneAccount mAccount;
- public ConnectionRequest(Uri handle, Bundle extras) {
- this(null, handle, extras);
- }
-
public ConnectionRequest(String callId, Uri handle, Bundle extras) {
this(null, callId, handle, extras);
}
diff --git a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
index 61c2b8a..50bec33 100644
--- a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
@@ -18,6 +18,7 @@
import android.net.wifi.ScanResult;
import android.net.wifi.passpoint.WifiPasspointPolicy;
+import android.net.wifi.passpoint.WifiPasspointCredential;
import android.os.Messenger;
/**
@@ -28,7 +29,17 @@
interface IWifiPasspointManager
{
Messenger getMessenger();
+
int getPasspointState();
+
List<WifiPasspointPolicy> requestCredentialMatch(in List<ScanResult> requested);
+
+ List<WifiPasspointCredential> getCredentials();
+
+ boolean addCredential(in WifiPasspointCredential cred);
+
+ boolean updateCredential(in WifiPasspointCredential cred);
+
+ boolean removeCredential(in WifiPasspointCredential cred);
}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
index 33ccad5..0a7230f 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
@@ -333,7 +333,7 @@
* Set the fully qualified domain name (FQDN) of this Passpoint credential.
* @param fqdn FQDN
*/
- public void setFqdn(String fqdn) {
+ public void setHomeFqdn(String fqdn) {
mHomeSpFqdn = fqdn;
}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
index ddca85e..b9b17eb 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
@@ -496,7 +496,11 @@
* @return The list of credentials
*/
public List<WifiPasspointCredential> getCredentials() {
- return null;
+ try {
+ return mService.getCredentials();
+ } catch (RemoteException e) {
+ return null;
+ }
}
/**
@@ -506,7 +510,11 @@
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public boolean addCredential(WifiPasspointCredential cred) {
- return true;
+ try {
+ return mService.addCredential(cred);
+ } catch (RemoteException e) {
+ return false;
+ }
}
/**
@@ -517,7 +525,11 @@
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public boolean updateCredential(WifiPasspointCredential cred) {
- return true;
+ try {
+ return mService.updateCredential(cred);
+ } catch (RemoteException e) {
+ return false;
+ }
}
/**
@@ -528,7 +540,11 @@
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public boolean removeCredential(WifiPasspointCredential cred) {
- return true;
+ try {
+ return mService.removeCredential(cred);
+ } catch (RemoteException e) {
+ return false;
+ }
}
public void startOsu(Channel c, WifiPasspointOsuProvider osu, OsuRemListener listener) {