From 78cc96af8ca9ef4f2edccbb1b5d494b3a357782d Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Tue, 12 Aug 2014 13:56:03 -0700 Subject: [PATCH 1/5] Anchoring the front most task to make the dismiss animation more stable. (Bug 16939699) Change-Id: I49aa14bbc7fdb2fb0884a8255af385dbbbe656f8 --- .../systemui/recents/views/TaskStackView.java | 22 ++++++++++++++++++- .../views/TaskStackViewLayoutAlgorithm.java | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 21b62e9c32970..aee558f88f65f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -395,7 +395,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Scroll the view into position (just center it in the curve) if (scrollToNewPosition) { - float newScroll = mLayoutAlgorithm.getStackScrollForTaskIndex(t) - 0.5f; + float newScroll = mLayoutAlgorithm.getStackScrollForTask(t) - 0.5f; newScroll = mStackScroller.getBoundedStackScroll(newScroll); mStackScroller.animateScroll(mStackScroller.getStackScroll(), newScroll, postScrollRunnable); } else { @@ -681,8 +681,28 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Notify the callback that we've removed the task and it can clean up after it mCb.onTaskViewDismissed(removedTask); + // Get the stack scroll of the task to anchor to (since we are removing something, the front + // most task will be our anchor task) + Task anchorTask = null; + float prevAnchorTaskScroll = 0; + boolean pullStackForward = stack.getTaskCount() > 0; + if (pullStackForward) { + anchorTask = mStack.getFrontMostTask(); + prevAnchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask); + } + // Update the min/max scroll and animate other task views into their new positions updateMinMaxScroll(true, mConfig.launchedWithAltTab, mConfig.launchedFromHome); + + // Offset the stack by as much as the anchor task would otherwise move back + if (pullStackForward) { + float anchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask); + mStackScroller.setStackScroll(mStackScroller.getStackScroll() + (anchorTaskScroll + - prevAnchorTaskScroll)); + mStackScroller.boundScroll(); + } + + // Animate all the tasks into place requestSynchronizeStackViewsWithModel(200); // Update the new front most task diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java index 495d00b1fa313..667faa7dfbc9d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java @@ -202,7 +202,7 @@ public class TaskStackViewLayoutAlgorithm { /** * Returns the scroll to such task top = 1f; */ - float getStackScrollForTaskIndex(Task t) { + float getStackScrollForTask(Task t) { return mTaskProgressMap.get(t.key); } From 7ed8901f120b21b4476c37b47791e25d659b21a5 Mon Sep 17 00:00:00 2001 From: Wonsik Kim Date: Thu, 14 Aug 2014 16:32:37 +0900 Subject: [PATCH 2/5] TIF: fix IOException at PersistentDataStore.save() Bug: 17018435 Change-Id: Ic999aaf59ae942ee8279576ec1e2ce2fa62bd6e0 --- .../core/java/com/android/server/tv/PersistentDataStore.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/tv/PersistentDataStore.java b/services/core/java/com/android/server/tv/PersistentDataStore.java index 4af8f2c266b2d..ed0de03bce359 100644 --- a/services/core/java/com/android/server/tv/PersistentDataStore.java +++ b/services/core/java/com/android/server/tv/PersistentDataStore.java @@ -81,8 +81,9 @@ final class PersistentDataStore { public PersistentDataStore(Context context, int userId) { mContext = context; - mAtomicFile = new AtomicFile(new File("/data/system/tv/" + userId - + "/tv-input-manager-state.xml")); + File tvDir = new File("/data/system/tv/" + userId); + tvDir.mkdirs(); + mAtomicFile = new AtomicFile(new File(tvDir, "tv-input-manager-state.xml")); } public boolean isParentalControlsEnabled() { From 0dac35af2c6aa42bcd181981b041747cfd1afa5f Mon Sep 17 00:00:00 2001 From: RoboErik Date: Tue, 12 Aug 2014 15:48:49 -0700 Subject: [PATCH 3/5] Pipe caller's identity through volume methods setStreamVolume and adjustStreamVolume were always being called from the session service's uid/package. This adds the plumbing to allow the original app's info to be passed in to the audio service when volume is changed. Change-Id: Ib36639dab1e518b435161dc453c8ba9351df3e9b --- .../android/media/AudioManagerInternal.java | 34 +++++++++++++++++ media/java/android/media/AudioService.java | 38 +++++++++++++++++-- .../media/session/ISessionController.aidl | 4 +- .../media/session/MediaController.java | 4 +- .../server/media/MediaSessionRecord.java | 24 ++++++++---- .../server/media/MediaSessionService.java | 3 +- 6 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 media/java/android/media/AudioManagerInternal.java diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java new file mode 100644 index 0000000000000..6f1bdef873037 --- /dev/null +++ b/media/java/android/media/AudioManagerInternal.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.media; + +import com.android.server.LocalServices; + +/** + * Class for system services to access extra AudioManager functionality. The + * AudioService is responsible for registering an implementation with + * {@link LocalServices}. + * + * @hide + */ +public abstract class AudioManagerInternal { + + public abstract void adjustStreamVolumeForUid(int streamType, int direction, int flags, + String callingPackage, int uid); + + public abstract void setStreamVolumeForUid(int streamType, int direction, int flags, + String callingPackage, int uid); +} diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index c6489a63c3fd9..48059a1353454 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -79,6 +79,7 @@ import android.view.WindowManager; import com.android.internal.telephony.ITelephony; import com.android.internal.util.XmlUtils; +import com.android.server.LocalServices; import org.xmlpull.v1.XmlPullParserException; @@ -635,6 +636,7 @@ public class AudioService extends IAudioService.Stub { mMasterVolumeRamp = context.getResources().getIntArray( com.android.internal.R.array.config_masterVolumeRamp); + LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal()); } public void systemReady() { @@ -956,6 +958,11 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#adjustStreamVolume(int, int, int) */ public void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage) { + adjustStreamVolume(streamType, direction, flags, callingPackage, Binder.getCallingUid()); + } + + private void adjustStreamVolume(int streamType, int direction, int flags, + String callingPackage, int uid) { if (mUseFixedVolume) { return; } @@ -984,8 +991,8 @@ public class AudioService extends IAudioService.Stub { return; } - if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(), - callingPackage) != AppOpsManager.MODE_ALLOWED) { + if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage) + != AppOpsManager.MODE_ALLOWED) { return; } @@ -1161,6 +1168,11 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#setStreamVolume(int, int, int) */ public void setStreamVolume(int streamType, int index, int flags, String callingPackage) { + setStreamVolume(streamType, index, flags, callingPackage, Binder.getCallingUid()); + } + + private void setStreamVolume(int streamType, int index, int flags, String callingPackage, + int uid) { if (mUseFixedVolume) { return; } @@ -1179,8 +1191,8 @@ public class AudioService extends IAudioService.Stub { return; } - if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(), - callingPackage) != AppOpsManager.MODE_ALLOWED) { + if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage) + != AppOpsManager.MODE_ALLOWED) { return; } @@ -5347,6 +5359,24 @@ public class AudioService extends IAudioService.Stub { } } + /** + * Interface for system components to get some extra functionality through + * LocalServices. + */ + final class AudioServiceInternal extends AudioManagerInternal { + @Override + public void adjustStreamVolumeForUid(int streamType, int direction, int flags, + String callingPackage, int uid) { + adjustStreamVolume(streamType, direction, flags, callingPackage, uid); + } + + @Override + public void setStreamVolumeForUid(int streamType, int direction, int flags, + String callingPackage, int uid) { + setStreamVolume(streamType, direction, flags, callingPackage, uid); + } + } + //========================================================================================== // Audio policy management //========================================================================================== diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl index 3518458fe706b..5764bd15cc103 100644 --- a/media/java/android/media/session/ISessionController.aidl +++ b/media/java/android/media/session/ISessionController.aidl @@ -48,8 +48,8 @@ interface ISessionController { PendingIntent getLaunchPendingIntent(); long getFlags(); ParcelableVolumeInfo getVolumeAttributes(); - void adjustVolume(int direction, int flags); - void setVolumeTo(int value, int flags); + void adjustVolume(int direction, int flags, String packageName); + void setVolumeTo(int value, int flags, String packageName); IMediaRouterDelegate createMediaRouterDelegate(IMediaRouterStateCallback callback); diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index f6e189aade1ef..d649dbd7348d5 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -310,7 +310,7 @@ public final class MediaController { */ public void setVolumeTo(int value, int flags) { try { - mSessionBinder.setVolumeTo(value, flags); + mSessionBinder.setVolumeTo(value, flags, mContext.getPackageName()); } catch (RemoteException e) { Log.wtf(TAG, "Error calling setVolumeTo.", e); } @@ -331,7 +331,7 @@ public final class MediaController { */ public void adjustVolume(int direction, int flags) { try { - mSessionBinder.adjustVolume(direction, flags); + mSessionBinder.adjustVolume(direction, flags, mContext.getPackageName()); } catch (RemoteException e) { Log.wtf(TAG, "Error calling adjustVolumeBy.", e); } diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index e549ead6a0346..bb434c8d7a6c3 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -22,6 +22,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ParceledListSlice; import android.media.AudioManager; +import android.media.AudioManagerInternal; import android.media.MediaMetadata; import android.media.Rating; import android.media.VolumeProvider; @@ -52,6 +53,8 @@ import android.util.Log; import android.util.Slog; import android.view.KeyEvent; +import com.android.server.LocalServices; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.UUID; @@ -111,6 +114,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { // Volume handling fields private AudioAttributes mAudioAttrs; private AudioManager mAudioManager; + private AudioManagerInternal mAudioManagerInternal; private int mVolumeType = MediaSession.PLAYBACK_TYPE_LOCAL; private int mVolumeControlType = VolumeProvider.VOLUME_CONTROL_ABSOLUTE; private int mMaxVolume = 0; @@ -134,6 +138,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mService = service; mHandler = new MessageHandler(handler.getLooper()); mAudioManager = (AudioManager) service.getContext().getSystemService(Context.AUDIO_SERVICE); + mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class); mAudioAttrs = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(); } @@ -227,7 +232,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { * * @param direction The direction to adjust volume in. */ - public void adjustVolume(int direction, int flags) { + public void adjustVolume(int direction, int flags, String packageName, int uid) { if (isPlaybackActive(false)) { flags &= ~AudioManager.FLAG_PLAY_SOUND; } @@ -238,7 +243,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } if (mVolumeType == MediaSession.PLAYBACK_TYPE_LOCAL) { int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs); - mAudioManager.adjustStreamVolume(stream, direction, flags); + mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags, packageName, + uid); } else { if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) { // Nothing to do, the volume cannot be changed @@ -262,10 +268,10 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } } - public void setVolumeTo(int value, int flags) { + public void setVolumeTo(int value, int flags, String packageName, int uid) { if (mVolumeType == MediaSession.PLAYBACK_TYPE_LOCAL) { int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs); - mAudioManager.setStreamVolume(stream, value, flags); + mAudioManagerInternal.setStreamVolumeForUid(stream, value, flags, packageName, uid); } else { if (mVolumeControlType != VolumeProvider.VOLUME_CONTROL_ABSOLUTE) { // Nothing to do. The volume can't be set directly. @@ -984,20 +990,22 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public void adjustVolume(int direction, int flags) { + public void adjustVolume(int direction, int flags, String packageName) { + int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { - MediaSessionRecord.this.adjustVolume(direction, flags); + MediaSessionRecord.this.adjustVolume(direction, flags, packageName, uid); } finally { Binder.restoreCallingIdentity(token); } } @Override - public void setVolumeTo(int value, int flags) { + public void setVolumeTo(int value, int flags, String packageName) { + int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { - MediaSessionRecord.this.setVolumeTo(value, flags); + MediaSessionRecord.this.setVolumeTo(value, flags, packageName, uid); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index 0514f48fc6d01..1221aa4af10f2 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -812,7 +812,8 @@ public class MediaSessionService extends SystemService implements Monitor { Log.e(TAG, "Error adjusting default volume.", e); } } else { - session.adjustVolume(direction, flags); + session.adjustVolume(direction, flags, getContext().getPackageName(), + UserHandle.myUserId()); if (session.getPlaybackType() == MediaSession.PLAYBACK_TYPE_REMOTE && mRvc != null) { try { From b1a50f2dff3d2d24c3567e2be67e7a4bc87a9b31 Mon Sep 17 00:00:00 2001 From: Fabrice Di Meglio Date: Wed, 13 Aug 2014 10:41:40 -0700 Subject: [PATCH 4/5] Fix bug #16957601 Stability: ISE in Settings: Observer com.android.settings. SettingsPreferenceFragment$1@273c8fdb was not registered - add onUnbindPreferences() call to match onBindPreferences() - this new method is @hide so it does not impact the APIs Change-Id: Iee0ab8a4ecc2046f89fb96cc52af150e835f658c --- core/java/android/preference/PreferenceFragment.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java index acd79424fbbeb..e95e6e21b2518 100644 --- a/core/java/android/preference/PreferenceFragment.java +++ b/core/java/android/preference/PreferenceFragment.java @@ -258,6 +258,7 @@ public abstract class PreferenceFragment extends Fragment implements */ public void setPreferenceScreen(PreferenceScreen preferenceScreen) { if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) { + onUnbindPreferences(); mHavePrefs = true; if (mInitDone) { postBindPreferences(); @@ -349,6 +350,10 @@ public abstract class PreferenceFragment extends Fragment implements protected void onBindPreferences() { } + /** @hide */ + protected void onUnbindPreferences() { + } + /** @hide */ public ListView getListView() { ensureList(); From 78c64cdbd82a4d8feb7faf43109b86ab87252dd1 Mon Sep 17 00:00:00 2001 From: RoboErik Date: Thu, 14 Aug 2014 18:42:09 -0700 Subject: [PATCH 5/5] Fix crash in legacy apps that register without a looper Some legacy apps registered their media button receiver in a thread without a looper. If this happens we need to use the main looper to prevent a crash. bug: 16306226 Change-Id: Idf472e649393e2a7ce2a3e1cbb3476003ab17f34 --- cmds/media/src/com/android/commands/media/Media.java | 10 +++++++++- .../media/session/MediaSessionLegacyHelper.java | 7 +++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java index b13b0093db360..b37f896c6c42b 100644 --- a/cmds/media/src/com/android/commands/media/Media.java +++ b/cmds/media/src/com/android/commands/media/Media.java @@ -225,7 +225,7 @@ public class Media extends BaseCommand { void printUsageMessage() { try { System.out.println("V2Monitoring session " + mController.getTag() - + "... available commands:"); + + "... available commands: play, pause, next, previous"); } catch (RemoteException e) { System.out.println("Error trying to monitor session!"); } @@ -257,6 +257,14 @@ public class Media extends BaseCommand { addNewline = false; } else if ("q".equals(line) || "quit".equals(line)) { break; + } else if ("play".equals(line)) { + mController.play(); + } else if ("pause".equals(line)) { + mController.pause(); + } else if ("next".equals(line)) { + mController.next(); + } else if ("previous".equals(line)) { + mController.previous(); } else { System.out.println("Invalid command: " + line); } diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java index a182982e2a7cf..aa196a9fea48a 100644 --- a/media/java/android/media/session/MediaSessionLegacyHelper.java +++ b/media/java/android/media/session/MediaSessionLegacyHelper.java @@ -290,7 +290,6 @@ public class MediaSessionLegacyHelper { if (DEBUG) { Log.d(TAG, "addMediaButtonListener already added " + pi); } - return; } holder.mMediaButtonListener = new MediaButtonListener(pi, context); // TODO determine if handling transport performer commands should also @@ -468,7 +467,11 @@ public class MediaSessionLegacyHelper { mSessions.remove(mPi); } else if (mCb == null) { mCb = new SessionCallback(); - mSession.setCallback(mCb); + Handler handler = null; + if (Looper.myLooper() == null) { + handler = new Handler(Looper.getMainLooper()); + } + mSession.setCallback(mCb, handler); } }