diff options
21 files changed, 249 insertions, 1048 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 3209169..afd82e3 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -111,6 +111,7 @@ package android { field public static final java.lang.String INVOKE_CARRIER_SETUP = "android.permission.INVOKE_CARRIER_SETUP"; field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES"; field public static final java.lang.String KILL_UID = "android.permission.KILL_UID"; + field public static final java.lang.String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS"; field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE"; field public static final java.lang.String LOOP_RADIO = "android.permission.LOOP_RADIO"; field public static final java.lang.String MANAGE_ACCOUNTS = "android.permission.MANAGE_ACCOUNTS"; diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 1e9bc54..15cfbcd 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2466,13 +2466,6 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } - case SYSTEM_BACKUP_RESTORED: { - data.enforceInterface(IActivityManager.descriptor); - systemBackupRestored(); - reply.writeNoException(); - return true; - } - case NOTIFY_CLEARTEXT_NETWORK_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); final int uid = data.readInt(); @@ -5759,17 +5752,6 @@ class ActivityManagerProxy implements IActivityManager } @Override - public void systemBackupRestored() throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(IActivityManager.descriptor); - mRemote.transact(SYSTEM_BACKUP_RESTORED, data, reply, 0); - reply.readException(); - data.recycle(); - reply.recycle(); - } - - @Override public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 05a936c..4ba1055 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -488,7 +488,6 @@ public interface IActivityManager extends IInterface { public void notifyLaunchTaskBehindComplete(IBinder token) throws RemoteException; public void notifyEnterAnimationComplete(IBinder token) throws RemoteException; - public void systemBackupRestored() throws RemoteException; public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException; public void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize, @@ -825,7 +824,6 @@ public interface IActivityManager extends IInterface { int START_IN_PLACE_ANIMATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+240; int CHECK_PERMISSION_WITH_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+241; int REGISTER_TASK_STACK_LISTENER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+242; - int SYSTEM_BACKUP_RESTORED = IBinder.FIRST_CALL_TRANSACTION+243; // Start of M transactions int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+280; diff --git a/core/java/android/app/backup/RecentsBackupHelper.java b/core/java/android/app/backup/RecentsBackupHelper.java deleted file mode 100644 index 1a64da6..0000000 --- a/core/java/android/app/backup/RecentsBackupHelper.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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.app.backup; - -import android.content.Context; -import android.os.Environment; -import android.os.ParcelFileDescriptor; -import android.util.Slog; - -import java.io.File; - -/** - * Helper for saving/restoring 'recent tasks' infrastructure. - * @hide - */ -public class RecentsBackupHelper implements BackupHelper { - private static final String TAG = "RecentsBackup"; - private static final boolean DEBUG = false; - - // This must match TaskPersister.TASKS_DIRNAME, but that class is not accessible from here - private static final String RECENTS_TASK_DIR = "recent_tasks"; - - // Must match TaskPersister.IMAGES_DIRNAME, as above - private static final String RECENTS_IMAGE_DIR = "recent_images"; - - // At restore time, tasks/thumbnails are placed in these directories alongside - // the "live" recents dirs named above. - private static final String RECENTS_TASK_RESTORE_DIR = "restored_" + RECENTS_TASK_DIR; - private static final String RECENTS_IMAGE_RESTORE_DIR = "restored_" + RECENTS_IMAGE_DIR; - - // Prefixes for tagging the two kinds of recents backup records that we might generate - private static final String RECENTS_TASK_KEY = "task:"; - private static final String RECENTS_IMAGE_KEY = "image:"; - - FileBackupHelperBase mTaskFileHelper; - - final File mSystemDir; - final File mTasksDir; - final File mRestoredTasksDir; - final File mRestoredImagesDir; - final String[] mRecentFiles; - final String[] mRecentKeys; - - /** - * @param context The agent context in which this helper instance will run - */ - public RecentsBackupHelper(Context context) { - mTaskFileHelper = new FileBackupHelperBase(context); - - mSystemDir = new File(Environment.getDataDirectory(), "system"); - mTasksDir = new File(mSystemDir, RECENTS_TASK_DIR); - mRestoredTasksDir = new File(mSystemDir, RECENTS_TASK_RESTORE_DIR); - mRestoredImagesDir = new File(mSystemDir, RECENTS_IMAGE_RESTORE_DIR); - - // Currently we back up only the recent-task descriptions, not the thumbnails - File[] recentFiles = mTasksDir.listFiles(); - if (recentFiles != null) { - // We explicitly proceed even if this is a zero-size array - final int N = recentFiles.length; - mRecentKeys = new String[N]; - mRecentFiles = new String[N]; - if (DEBUG) { - Slog.i(TAG, "Identifying recents for backup: " + N); - } - for (int i = 0; i < N; i++) { - mRecentKeys[i] = new String(RECENTS_TASK_KEY + recentFiles[i].getName()); - mRecentFiles[i] = recentFiles[i].getAbsolutePath(); - if (DEBUG) { - Slog.i(TAG, " " + mRecentKeys[i]); - } - } - } else { - mRecentFiles = mRecentKeys = new String[0]; - } - } - - /** - * Task-file key: RECENTS_TASK_KEY + leaf filename - * Thumbnail-file key: RECENTS_IMAGE_KEY + leaf filename - */ - @Override - public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data, - ParcelFileDescriptor newState) { - FileBackupHelperBase.performBackup_checked(oldState, data, newState, - mRecentFiles, mRecentKeys); - } - - @Override - public void restoreEntity(BackupDataInputStream data) { - final String key = data.getKey(); - File output = null; - if (key.startsWith(RECENTS_TASK_KEY)) { - String name = key.substring(RECENTS_TASK_KEY.length()); - output = new File(mRestoredTasksDir, name); - mRestoredTasksDir.mkdirs(); - } else if (key.startsWith(RECENTS_IMAGE_KEY)) { - String name = key.substring(RECENTS_IMAGE_KEY.length()); - output = new File(mRestoredImagesDir, name); - mRestoredImagesDir.mkdirs(); - } - - if (output != null) { - if (DEBUG) { - Slog.i(TAG, "Restoring key='" - + key + "' to " + output.getAbsolutePath()); - } - mTaskFileHelper.writeFile(output, data); - } - } - - @Override - public void writeNewStateDescription(ParcelFileDescriptor newState) { - mTaskFileHelper.writeNewStateDescription(newState); - } - -} diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 8768f40..b22b914 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -96,6 +96,14 @@ public final class BluetoothAdapter { private static final boolean VDBG = false; /** + * Default MAC address reported to a client that does not have the + * android.permission.LOCAL_MAC_ADDRESS permission. + * + * @hide + */ + public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; + + /** * Sentinel error value for this class. Guaranteed to not equal any other * integer constant in this class. Provided as a convenience for functions * that require a sentinel error value, for example: diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java index f18b7ac..bd45007 100644 --- a/core/java/android/view/ViewPropertyAnimator.java +++ b/core/java/android/view/ViewPropertyAnimator.java @@ -80,18 +80,12 @@ public class ViewPropertyAnimator { /** * The interpolator of the underlying Animator object. By default, we don't set the interpolator - * on the Animator and just use its default interpolator. If the interpolator is ever set on - * this Animator, then we use the interpolator that it was set to. + * on the Animator and just use its default interpolator. If the interpolator is set to a + * non-null value on this Animator, then we use the interpolator that it was set to. */ private TimeInterpolator mInterpolator; /** - * A flag indicating whether the interpolator has been set on this object. If not, we don't set - * the interpolator on the underlying Animator, but instead just use its default interpolator. - */ - private boolean mInterpolatorSet = false; - - /** * Listener for the lifecycle events of the underlying ValueAnimator object. */ private Animator.AnimatorListener mListener = null; @@ -338,7 +332,6 @@ public class ViewPropertyAnimator { * @return This object, allowing calls to methods in this class to be chained. */ public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) { - mInterpolatorSet = true; mInterpolator = interpolator; return this; } @@ -349,7 +342,7 @@ public class ViewPropertyAnimator { * @return The timing interpolator for this animation. */ public TimeInterpolator getInterpolator() { - if (mInterpolatorSet) { + if (mInterpolator != null) { return mInterpolator; } else { // Just return the default from ValueAnimator, since that's what we'd get if @@ -897,7 +890,7 @@ public class ViewPropertyAnimator { if (mDurationSet) { animator.setDuration(mDuration); } - if (mInterpolatorSet) { + if (mInterpolator != null) { animator.setInterpolator(mInterpolator); } animator.start(); diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java index a80abce..f485460 100644 --- a/core/java/com/android/server/backup/SystemBackupAgent.java +++ b/core/java/com/android/server/backup/SystemBackupAgent.java @@ -16,14 +16,12 @@ package com.android.server.backup; -import android.app.ActivityManagerNative; import android.app.IWallpaperManager; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.app.backup.BackupAgentHelper; import android.app.backup.FullBackup; import android.app.backup.FullBackupDataOutput; -import android.app.backup.RecentsBackupHelper; import android.app.backup.WallpaperBackupHelper; import android.content.Context; import android.os.Environment; @@ -45,7 +43,6 @@ public class SystemBackupAgent extends BackupAgentHelper { // Names of the helper tags within the dataset. Changing one of these names will // break the ability to restore from datasets that predate the change. private static final String WALLPAPER_HELPER = "wallpaper"; - private static final String RECENTS_HELPER = "recents"; private static final String SYNC_SETTINGS_HELPER = "account_sync_settings"; private static final String PREFERRED_HELPER = "preferred_activities"; private static final String NOTIFICATION_HELPER = "notifications"; @@ -92,7 +89,6 @@ public class SystemBackupAgent extends BackupAgentHelper { } } addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this, files, keys)); - addHelper(RECENTS_HELPER, new RecentsBackupHelper(this)); addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this)); addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper()); addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this)); @@ -127,7 +123,6 @@ public class SystemBackupAgent extends BackupAgentHelper { addHelper("system_files", new WallpaperBackupHelper(this, new String[] { WALLPAPER_IMAGE }, new String[] { WALLPAPER_IMAGE_KEY} )); - addHelper(RECENTS_HELPER, new RecentsBackupHelper(this)); addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this)); addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper()); addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this)); @@ -200,13 +195,4 @@ public class SystemBackupAgent extends BackupAgentHelper { } } } - - @Override - public void onRestoreFinished() { - try { - ActivityManagerNative.getDefault().systemBackupRestored(); - } catch (RemoteException e) { - // Not possible since this code is running in the system process. - } - } } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 608d718..595f9f0 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -898,7 +898,9 @@ android:label="@string/permlab_changeWimaxState" android:protectionLevel="dangerous" /> - <!-- Allows applications to act as network scorers. @hide @SystemApi--> + <!--@SystemApi Allows applications to the the local WiFi and Bluetooth MAC address. + @hide + --> <permission android:name="android.permission.SCORE_NETWORKS" android:protectionLevel="signature|system" /> @@ -2447,6 +2449,10 @@ <permission android:name="android.permission.KILL_UID" android:protectionLevel="signature" /> + <!-- Allows applications to act as network scorers. @hide @SystemApi--> + <permission android:name="android.permission.LOCAL_MAC_ADDRESS" + android:protectionLevel="signature" /> + <!-- The system process is explicitly the only one allowed to launch the confirmation UI for full backup/restore --> <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/> diff --git a/docs/html/preview/index.jd b/docs/html/preview/index.jd index 2801c18..3b5fdbd 100644 --- a/docs/html/preview/index.jd +++ b/docs/html/preview/index.jd @@ -22,21 +22,9 @@ footer.hide=1 Test your apps and give us feedback! </p> - <a class="dac-hero-cta" href="{@docRoot}preview/overview.html"> - <span class="dac-sprite dac-auto-chevron"></span> - Preview Program Overview - </a><br> - <a class="dac-hero-cta" href="{@docRoot}preview/api-overview.html"> - <span class="dac-sprite dac-auto-chevron"></span> - Review the API changes - </a><br> <a class="dac-hero-cta" href="{@docRoot}preview/setup-sdk.html"> <span class="dac-sprite dac-auto-chevron"></span> - Set up the Preview SDK - </a><br> - <a class="dac-hero-cta" href="https://code.google.com/p/android-developer-preview/"> - <span class="dac-sprite dac-auto-chevron"></span> - Report issues + Get started </a><br> </div> @@ -55,6 +43,7 @@ footer.hide=1 <i class="dac-sprite dac-arrow-down-gray"></i> </a> </div> + <section class="dac-section dac-gray dac-small dac-invert" id="latest"><div class="wrap"> <h2 class="norule">Latest</h2> <div class="resource-widget resource-flow-layout col-16" @@ -62,22 +51,3 @@ footer.hide=1 data-cardSizes="6x6" data-maxResults="3"></div> </div></section> - -<section class="dac-section dac-light"><div class="wrap"> - <h1 class="dac-section-title">Android Data Binding</h1> - <div class="dac-section-subtitle"> - A new way to manage your app's UI. - </div> - - <ul class="dac-section-links"> - <li class="dac-section-link"><a href=""> - <span class="dac-sprite dac-auto-chevron"></span> - Overview and Usage - </a></li> - <li class="dac-section-link"><a href="/google/play/filters.html"> - <span class="dac-sprite dac-auto-chevron"></span> - User Guide - </a></li> - - </ul> -</div></section>
\ No newline at end of file diff --git a/docs/html/tools/devices/index.jd b/docs/html/tools/devices/index.jd index 1ea4c47..6263c8b 100644 --- a/docs/html/tools/devices/index.jd +++ b/docs/html/tools/devices/index.jd @@ -5,16 +5,16 @@ page.title=Managing Virtual Devices <p>An Android Virtual Device (AVD) is an emulator configuration that lets you model an actual device by defining hardware and software options to be emulated by the Android Emulator.</p> - <p>The easiest way to create an AVD is to use the graphical <a href= - "{@docRoot}tools/devices/managing-avds.html">AVD Manager</a>, which you launch - from Eclipse by clicking <strong>Window > AVD Manager</strong>. You can also start the AVD -Manager from the command line by calling the <code>android</code> tool with the <code>avd</code> -options, from the <strong><sdk>/tools/</strong> directory.</p> + <p>The easiest way to create an AVD is to use the graphical + <a href="{@docRoot}tools/devices/managing-avds.html">AVD Manager</a>, which you launch + from Android Studio by clicking <strong>Tools > Android > AVD Manager</strong>. You can + also start the AVD Manager from the command line by calling the <code>android</code> tool with + the <code>avd</code> options, from the <strong><sdk>/tools/</strong> directory.</p> <p>You can also create AVDs on the command line by passing the <code>android</code> tool options. - For more information on how to create AVDs in this manner, see <a href= - "{@docRoot}tools/devices/managing-avds-cmdline.html">Managing Virtual - Devices from the Command Line</a>.</p> + For more information on how to create AVDs in this manner, see + <a href="{@docRoot}tools/devices/managing-avds-cmdline.html">Managing Virtual Devices from the + Command Line</a>.</p> <p>An AVD consists of:</p> diff --git a/docs/html/tools/devices/managing-avds-cmdline.jd b/docs/html/tools/devices/managing-avds-cmdline.jd index ba353c1..c16b1f8 100644 --- a/docs/html/tools/devices/managing-avds-cmdline.jd +++ b/docs/html/tools/devices/managing-avds-cmdline.jd @@ -84,8 +84,8 @@ id: 5 or "android-9" <h2 id="AVDCmdLine">Creating AVDs</h2> -<p>In addition to creating AVDs with the -<a href="{@docRoot}tools/devices/managing-avds-cmdline.html">AVD Manager user interface</a>, +<p>In addition to creating AVDs with the +<a href="{@docRoot}tools/help/avd-manager.html">AVD Manager user interface</a>, you can also create them by passing in command line arguments to the <code>android</code> tool. </p> diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index ea60040..28c26ff 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -19,7 +19,6 @@ import android.animation.AnimatorInflater; import android.animation.AnimatorSet; import android.animation.Animator.AnimatorListener; import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; @@ -128,19 +127,13 @@ import java.util.List; * @attr ref android.R.styleable#AnimatedVectorDrawableTarget_animation */ public class AnimatedVectorDrawable extends Drawable implements Animatable { - private static final String LOGTAG = "AnimatedVectorDrawable"; + private static final String LOGTAG = AnimatedVectorDrawable.class.getSimpleName(); private static final String ANIMATED_VECTOR = "animated-vector"; private static final String TARGET = "target"; private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false; - /** - * The resources against which this drawable was created. Used to attempt - * to inflate animators if applyTheme() doesn't get called. - */ - private Resources mRes; - private AnimatedVectorDrawableState mAnimatedVectorState; private boolean mMutated; @@ -151,7 +144,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res) { mAnimatedVectorState = new AnimatedVectorDrawableState(state, mCallback, res); - mRes = res; } @Override @@ -281,7 +273,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { @Override public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { - final AnimatedVectorDrawableState state = mAnimatedVectorState; int eventType = parser.getEventType(); float pathErrorScale = 1; @@ -299,10 +290,10 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { vectorDrawable.setAllowCaching(false); vectorDrawable.setCallback(mCallback); pathErrorScale = vectorDrawable.getPixelSize(); - if (state.mVectorDrawable != null) { - state.mVectorDrawable.setCallback(null); + if (mAnimatedVectorState.mVectorDrawable != null) { + mAnimatedVectorState.mVectorDrawable.setCallback(null); } - state.mVectorDrawable = vectorDrawable; + mAnimatedVectorState.mVectorDrawable = vectorDrawable; } a.recycle(); } else if (TARGET.equals(tagName)) { @@ -311,25 +302,12 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { final String target = a.getString( R.styleable.AnimatedVectorDrawableTarget_name); - final int animResId = a.getResourceId( + int id = a.getResourceId( R.styleable.AnimatedVectorDrawableTarget_animation, 0); - if (animResId != 0) { - if (theme != null) { - final Animator objectAnimator = AnimatorInflater.loadAnimator( - res, theme, animResId, pathErrorScale); - setupAnimatorsForTarget(target, objectAnimator); - } else { - // The animation may be theme-dependent. As a - // workaround until Animator has full support for - // applyTheme(), postpone loading the animator - // until we have a theme in applyTheme(). - if (state.mPendingAnims == null) { - state.mPendingAnims = new ArrayList<>(1); - } - state.mPendingAnims.add( - new PendingAnimator(animResId, pathErrorScale, target)); - - } + if (id != 0) { + Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id, + pathErrorScale); + setupAnimatorsForTarget(target, objectAnimator); } a.recycle(); } @@ -337,13 +315,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { eventType = parser.next(); } - - // If we don't have any pending animations, we don't need to hold a - // reference to the resources. - if (state.mPendingAnims == null) { - mRes = null; - } - setupAnimatorSet(); } @@ -369,29 +340,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { if (vectorDrawable != null && vectorDrawable.canApplyTheme()) { vectorDrawable.applyTheme(t); } - - if (t != null) { - inflatePendingAnimators(t.getResources(), t); - } - } - - /** - * Inflates pending animators, if any, against a theme. Clears the list of - * pending animators. - * - * @param t the theme against which to inflate the animators - */ - private void inflatePendingAnimators(@NonNull Resources res, @Nullable Theme t) { - final ArrayList<PendingAnimator> pendingAnims = mAnimatedVectorState.mPendingAnims; - if (pendingAnims != null) { - mAnimatedVectorState.mPendingAnims = null; - - for (int i = 0, count = pendingAnims.size(); i < count; i++) { - final PendingAnimator pendingAnimator = pendingAnims.get(i); - final Animator objectAnimator = pendingAnimator.newInstance(res, t); - setupAnimatorsForTarget(pendingAnimator.target, objectAnimator); - } - } } /** @@ -433,7 +381,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { // we add this array into the mAnimatorSet. private ArrayList<Animator> mTempAnimators; ArrayMap<Animator, String> mTargetNameMap; - ArrayList<PendingAnimator> mPendingAnims; public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy, Callback owner, Resources res) { @@ -456,7 +403,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { final int numAnimators = copy.mTargetNameMap.size(); // Deep copy a animator set, and then setup the target map again. mAnimatorSet = copy.mAnimatorSet.clone(); - mTargetNameMap = new ArrayMap<>(numAnimators); + mTargetNameMap = new ArrayMap<Animator, String>(numAnimators); // Since the new AnimatorSet is cloned from the old one, the order must be the // same inside the array. ArrayList<Animator> oldAnim = copy.mAnimatorSet.getChildAnimations(); @@ -471,9 +418,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { mTargetNameMap.put(newAnim.get(i), targetName); } } - - // Shallow copy since the array is immutable after inflate(). - mPendingAnims = copy.mPendingAnims; } else { mVectorDrawable = new VectorDrawable(); } @@ -482,7 +426,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { @Override public boolean canApplyTheme() { return (mVectorDrawable != null && mVectorDrawable.canApplyTheme()) - || mPendingAnims != null || super.canApplyTheme(); + || super.canApplyTheme(); } @Override @@ -501,32 +445,12 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { } } - /** - * Basically a constant state for Animators until we actually implement - * constant states for Animators. - */ - private static class PendingAnimator { - public final int animResId; - public final float pathErrorScale; - public final String target; - - public PendingAnimator(int animResId, float pathErrorScale, String target) { - this.animResId = animResId; - this.pathErrorScale = pathErrorScale; - this.target = target; - } - - public Animator newInstance(Resources res, Theme theme) { - return AnimatorInflater.loadAnimator(res, theme, animResId, pathErrorScale); - } - } - private void setupAnimatorsForTarget(String name, Animator animator) { Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name); animator.setTarget(target); if (mAnimatedVectorState.mTempAnimators == null) { - mAnimatedVectorState.mTempAnimators = new ArrayList<>(); - mAnimatedVectorState.mTargetNameMap = new ArrayMap<>(); + mAnimatedVectorState.mTempAnimators = new ArrayList<Animator>(); + mAnimatedVectorState.mTargetNameMap = new ArrayMap<Animator, String>(); } mAnimatedVectorState.mTempAnimators.add(animator); mAnimatedVectorState.mTargetNameMap.put(animator, name); @@ -550,23 +474,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { if (isStarted()) { return; } - - // Check for uninflated animators. We can remove this after we add - // support for Animator.applyTheme(). See comments in inflate(). - if (mAnimatedVectorState.mPendingAnims != null) { - // Attempt to load animators without applying a theme. - if (mRes != null) { - inflatePendingAnimators(mRes, null); - mRes = null; - } else { - Log.e(LOGTAG, "Failed to load animators. Either the AnimatedVectorDrawable must be" - + " created using a Resources object or applyTheme() must be called with" - + " a non-null Theme object."); - } - - mAnimatedVectorState.mPendingAnims = null; - } - mAnimatedVectorState.mAnimatorSet.start(); invalidateSelf(); } diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 161a7ba7..d21762b 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -192,13 +192,20 @@ public class AudioTrack /** * The write mode indicating the write operation will block until all data has been written, - * to be used in {@link #write(ByteBuffer, int, int)} + * to be used as the actual value of the writeMode parameter in + * {@link #write(byte[], int, int, int)}, {@link #write(short[], int, int, int)}, + * {@link #write(float[], int, int, int)}, {@link #write(ByteBuffer, int, int)}, and + * {@link #write(ByteBuffer, int, int, long)}. */ public final static int WRITE_BLOCKING = 0; + /** * The write mode indicating the write operation will return immediately after - * queuing as much audio data for playback as possible without blocking, to be used in - * {@link #write(ByteBuffer, int, int)}. + * queuing as much audio data for playback as possible without blocking, + * to be used as the actual value of the writeMode parameter in + * {@link #write(ByteBuffer, int, int)}, {@link #write(short[], int, int, int)}, + * {@link #write(float[], int, int, int)}, {@link #write(ByteBuffer, int, int)}, and + * {@link #write(ByteBuffer, int, int, long)}. */ public final static int WRITE_NON_BLOCKING = 1; @@ -1458,14 +1465,27 @@ public class AudioTrack //-------------------- /** * Starts playing an AudioTrack. + * <p> * If track's creation mode is {@link #MODE_STATIC}, you must have called one of - * the {@link #write(byte[], int, int)}, {@link #write(short[], int, int)}, - * or {@link #write(float[], int, int, int)} methods. - * If the mode is {@link #MODE_STREAM}, you can optionally prime the - * output buffer by writing up to bufferSizeInBytes (from constructor) before starting. - * This priming will avoid an immediate underrun, but is not required. + * the write methods ({@link #write(byte[], int, int)}, {@link #write(byte[], int, int, int)}, + * {@link #write(short[], int, int)}, {@link #write(short[], int, int, int)}, + * {@link #write(float[], int, int, int)}, or {@link #write(ByteBuffer, int, int)}) prior to + * play(). + * <p> + * If the mode is {@link #MODE_STREAM}, you can optionally prime the data path prior to + * calling play(), by writing up to <code>bufferSizeInBytes</code> (from constructor). + * If you don’t call write() first, or if you call write() but with an insufficient amount of + * data, then the track will be in underrun state at play(). In this case, + * playback will not actually start playing until the data path is filled to a + * device-specific minimum level. This requirement for the path to be filled + * to a minimum level is also true when resuming audio playback after calling stop(). + * Similarly the buffer will need to be filled up again after + * the track underruns due to failure to call write() in a timely manner with sufficient data. + * For portability, an application should prime the data path to the maximum allowed + * by writing data until the write() method returns a short transfer count. + * This allows play() to start immediately, and reduces the chance of underrun. * - * @throws IllegalStateException + * @throws IllegalStateException if the track isn't properly initialized */ public void play() throws IllegalStateException { @@ -1570,21 +1590,30 @@ public class AudioTrack * or copies audio data for later playback (static buffer mode). * The format specified in the AudioTrack constructor should be * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array. - * In streaming mode, will block until all data has been written to the audio sink. + * <p> + * In streaming mode, the write will normally block until all the data has been enqueued for + * playback, and will return a full transfer count. However, if the track is stopped or paused + * on entry, or another thread interrupts the write by calling stop or pause, or an I/O error + * occurs during the write, then the write may return a short transfer count. + * <p> * In static buffer mode, copies the data to the buffer starting at offset 0. - * Note that the actual playback of this data might occur after this function - * returns. This function is thread safe with respect to {@link #stop} calls, - * in which case all of the specified data might not be written to the audio sink. + * Note that the actual playback of this data might occur after this function returns. * * @param audioData the array that holds the data to play. * @param offsetInBytes the offset expressed in bytes in audioData where the data to play * starts. * @param sizeInBytes the number of bytes to read in audioData after the offset. - * @return the number of bytes that were written or {@link #ERROR_INVALID_OPERATION} - * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if + * @return zero or the positive number of bytes that were written, or + * {@link #ERROR_INVALID_OPERATION} + * if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if * the parameters don't resolve to valid data and indexes, or * {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and * needs to be recreated. + * The dead object error code is not returned if some data was successfully transferred. + * In this case, the error is returned at the next write(). + * + * This is equivalent to {@link #write(byte[], int, int, int)} with <code>writeMode</code> + * set to {@link #WRITE_BLOCKING}. */ public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) { return write(audioData, offsetInBytes, sizeInBytes, WRITE_BLOCKING); @@ -1595,11 +1624,17 @@ public class AudioTrack * or copies audio data for later playback (static buffer mode). * The format specified in the AudioTrack constructor should be * {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array. - * In streaming mode, will block until all data has been written to the audio sink. - * In static buffer mode, copies the data to the buffer starting at offset 0. - * Note that the actual playback of this data might occur after this function - * returns. This function is thread safe with respect to {@link #stop} calls, - * in which case all of the specified data might not be written to the audio sink. + * <p> + * In streaming mode, the blocking behavior depends on the write mode. If the write mode is + * {@link #WRITE_BLOCKING}, the write will normally block until all the data has been enqueued + * for playback, and will return a full transfer count. However, if the write mode is + * {@link #WRITE_NON_BLOCKING}, or the track is stopped or paused on entry, or another thread + * interrupts the write by calling stop or pause, or an I/O error + * occurs during the write, then the write may return a short transfer count. + * <p> + * In static buffer mode, copies the data to the buffer starting at offset 0, + * and the write mode is ignored. + * Note that the actual playback of this data might occur after this function returns. * * @param audioData the array that holds the data to play. * @param offsetInBytes the offset expressed in bytes in audioData where the data to play @@ -1611,11 +1646,14 @@ public class AudioTrack * to the audio sink. * <br>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after * queuing as much audio data for playback as possible without blocking. - * @return the number of bytes that were written or {@link #ERROR_INVALID_OPERATION} - * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if + * @return zero or the positive number of bytes that were written, or + * {@link #ERROR_INVALID_OPERATION} + * if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if * the parameters don't resolve to valid data and indexes, or * {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and * needs to be recreated. + * The dead object error code is not returned if some data was successfully transferred. + * In this case, the error is returned at the next write(). */ public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes, @WriteMode int writeMode) { @@ -1653,21 +1691,30 @@ public class AudioTrack * or copies audio data for later playback (static buffer mode). * The format specified in the AudioTrack constructor should be * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array. - * In streaming mode, will block until all data has been written to the audio sink. + * <p> + * In streaming mode, the write will normally block until all the data has been enqueued for + * playback, and will return a full transfer count. However, if the track is stopped or paused + * on entry, or another thread interrupts the write by calling stop or pause, or an I/O error + * occurs during the write, then the write may return a short transfer count. + * <p> * In static buffer mode, copies the data to the buffer starting at offset 0. - * Note that the actual playback of this data might occur after this function - * returns. This function is thread safe with respect to {@link #stop} calls, - * in which case all of the specified data might not be written to the audio sink. + * Note that the actual playback of this data might occur after this function returns. * * @param audioData the array that holds the data to play. * @param offsetInShorts the offset expressed in shorts in audioData where the data to play * starts. * @param sizeInShorts the number of shorts to read in audioData after the offset. - * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION} - * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if + * @return zero or the positive number of shorts that were written, or + * {@link #ERROR_INVALID_OPERATION} + * if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if * the parameters don't resolve to valid data and indexes, or * {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and * needs to be recreated. + * The dead object error code is not returned if some data was successfully transferred. + * In this case, the error is returned at the next write(). + * + * This is equivalent to {@link #write(short[], int, int, int)} with <code>writeMode</code> + * set to {@link #WRITE_BLOCKING}. */ public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts) { return write(audioData, offsetInShorts, sizeInShorts, WRITE_BLOCKING); @@ -1678,11 +1725,16 @@ public class AudioTrack * or copies audio data for later playback (static buffer mode). * The format specified in the AudioTrack constructor should be * {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array. - * In streaming mode, will block until all data has been written to the audio sink. + * <p> + * In streaming mode, the blocking behavior depends on the write mode. If the write mode is + * {@link #WRITE_BLOCKING}, the write will normally block until all the data has been enqueued + * for playback, and will return a full transfer count. However, if the write mode is + * {@link #WRITE_NON_BLOCKING}, or the track is stopped or paused on entry, or another thread + * interrupts the write by calling stop or pause, or an I/O error + * occurs during the write, then the write may return a short transfer count. + * <p> * In static buffer mode, copies the data to the buffer starting at offset 0. - * Note that the actual playback of this data might occur after this function - * returns. This function is thread safe with respect to {@link #stop} calls, - * in which case all of the specified data might not be written to the audio sink. + * Note that the actual playback of this data might occur after this function returns. * * @param audioData the array that holds the data to play. * @param offsetInShorts the offset expressed in shorts in audioData where the data to play @@ -1694,11 +1746,14 @@ public class AudioTrack * to the audio sink. * <br>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after * queuing as much audio data for playback as possible without blocking. - * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION} - * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if + * @return zero or the positive number of shorts that were written, or + * {@link #ERROR_INVALID_OPERATION} + * if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if * the parameters don't resolve to valid data and indexes, or * {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and * needs to be recreated. + * The dead object error code is not returned if some data was successfully transferred. + * In this case, the error is returned at the next write(). */ public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts, @WriteMode int writeMode) { @@ -1736,14 +1791,18 @@ public class AudioTrack * or copies audio data for later playback (static buffer mode). * The format specified in the AudioTrack constructor should be * {@link AudioFormat#ENCODING_PCM_FLOAT} to correspond to the data in the array. - * In static buffer mode, copies the data to the buffer starting at offset 0, - * and the write mode is ignored. - * In streaming mode, the blocking behavior will depend on the write mode. * <p> - * Note that the actual playback of this data might occur after this function - * returns. This function is thread safe with respect to {@link #stop} calls, - * in which case all of the specified data might not be written to the audio sink. + * In streaming mode, the blocking behavior depends on the write mode. If the write mode is + * {@link #WRITE_BLOCKING}, the write will normally block until all the data has been enqueued + * for playback, and will return a full transfer count. However, if the write mode is + * {@link #WRITE_NON_BLOCKING}, or the track is stopped or paused on entry, or another thread + * interrupts the write by calling stop or pause, or an I/O error + * occurs during the write, then the write may return a short transfer count. * <p> + * In static buffer mode, copies the data to the buffer starting at offset 0, + * and the write mode is ignored. + * Note that the actual playback of this data might occur after this function returns. + * * @param audioData the array that holds the data to play. * The implementation does not clip for sample values within the nominal range * [-1.0f, 1.0f], provided that all gains in the audio pipeline are @@ -1763,11 +1822,14 @@ public class AudioTrack * to the audio sink. * <br>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after * queuing as much audio data for playback as possible without blocking. - * @return the number of floats that were written, or {@link #ERROR_INVALID_OPERATION} - * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if + * @return zero or the positive number of floats that were written, or + * {@link #ERROR_INVALID_OPERATION} + * if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if * the parameters don't resolve to valid data and indexes, or * {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and * needs to be recreated. + * The dead object error code is not returned if some data was successfully transferred. + * In this case, the error is returned at the next write(). */ public int write(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats, @WriteMode int writeMode) { @@ -1811,9 +1873,19 @@ public class AudioTrack /** * Writes the audio data to the audio sink for playback (streaming mode), * or copies audio data for later playback (static buffer mode). - * In static buffer mode, copies the data to the buffer starting at its 0 offset, and the write - * mode is ignored. - * In streaming mode, the blocking behavior will depend on the write mode. + * The audioData in ByteBuffer should match the format specified in the AudioTrack constructor. + * <p> + * In streaming mode, the blocking behavior depends on the write mode. If the write mode is + * {@link #WRITE_BLOCKING}, the write will normally block until all the data has been enqueued + * for playback, and will return a full transfer count. However, if the write mode is + * {@link #WRITE_NON_BLOCKING}, or the track is stopped or paused on entry, or another thread + * interrupts the write by calling stop or pause, or an I/O error + * occurs during the write, then the write may return a short transfer count. + * <p> + * In static buffer mode, copies the data to the buffer starting at offset 0, + * and the write mode is ignored. + * Note that the actual playback of this data might occur after this function returns. + * * @param audioData the buffer that holds the data to play, starting at the position reported * by <code>audioData.position()</code>. * <BR>Note that upon return, the buffer position (<code>audioData.position()</code>) will @@ -1827,10 +1899,12 @@ public class AudioTrack * to the audio sink. * <BR>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after * queuing as much audio data for playback as possible without blocking. - * @return 0 or a positive number of bytes that were written, or + * @return zero or the positive number of bytes that were written, or * {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}, or * {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and * needs to be recreated. + * The dead object error code is not returned if some data was successfully transferred. + * In this case, the error is returned at the next write(). */ public int write(@NonNull ByteBuffer audioData, int sizeInBytes, @WriteMode int writeMode) { @@ -1877,8 +1951,8 @@ public class AudioTrack } /** - * Writes the audio data to the audio sink for playback (streaming mode) on a HW_AV_SYNC track. - * In streaming mode, the blocking behavior will depend on the write mode. + * Writes the audio data to the audio sink for playback in streaming mode on a HW_AV_SYNC track. + * The blocking behavior will depend on the write mode. * @param audioData the buffer that holds the data to play, starting at the position reported * by <code>audioData.position()</code>. * <BR>Note that upon return, the buffer position (<code>audioData.position()</code>) will @@ -1892,10 +1966,12 @@ public class AudioTrack * <BR>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after * queuing as much audio data for playback as possible without blocking. * @param timestamp The timestamp of the first decodable audio frame in the provided audioData. - * @return 0 or a positive number of bytes that were written, or + * @return zero or a positive number of bytes that were written, or * {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}, or * {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and * needs to be recreated. + * The dead object error code is not returned if some data was successfully transferred. + * In this case, the error is returned at the next write(). */ public int write(ByteBuffer audioData, int sizeInBytes, @WriteMode int writeMode, long timestamp) { diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java index 1cabcdf..e03f449 100644 --- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java +++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java @@ -16,6 +16,7 @@ package com.android.keyguard; +import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; @@ -42,7 +43,7 @@ public class EmergencyButton extends Button { .setPackage("com.android.phone") .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS - | Intent.FLAG_ACTIVITY_CLEAR_TASK); + | Intent.FLAG_ACTIVITY_CLEAR_TOP); KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { @@ -127,6 +128,7 @@ public class EmergencyButton extends Button { KeyguardUpdateMonitor.getInstance(mContext).reportEmergencyCallAction( true /* bypassHandler */); getContext().startActivityAsUser(INTENT_EMERGENCY_DIAL, + ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(), new UserHandle(KeyguardUpdateMonitor.getCurrentUser())); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java index 17e2cb5..3feec9e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java @@ -59,6 +59,12 @@ public abstract class ExpandableView extends FrameLayout { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int ownMaxHeight = mMaxViewHeight; + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY; + if (hasFixedHeight) { + // We have a height set in our layout, so we want to be at most as big as given + ownMaxHeight = Math.min(MeasureSpec.getSize(heightMeasureSpec), ownMaxHeight); + } int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST); int maxChildHeight = 0; int childCount = getChildCount(); @@ -85,7 +91,7 @@ public abstract class ExpandableView extends FrameLayout { mMatchParentViews.add(child); } } - int ownHeight = Math.min(ownMaxHeight, maxChildHeight); + int ownHeight = hasFixedHeight ? ownMaxHeight : Math.min(ownMaxHeight, maxChildHeight); newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY); for (View child : mMatchParentViews) { child.measure(getChildMeasureSpec( diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index f5d27f9..c46fa76 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -16,6 +16,7 @@ package com.android.server; +import android.Manifest; import android.app.ActivityManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothProfile; @@ -909,16 +910,22 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mCallbacks.finishBroadcast(); } } + public String getAddress() { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, - "Need BLUETOOTH permission"); + "Need BLUETOOTH permission"); if ((Binder.getCallingUid() != Process.SYSTEM_UID) && - (!checkIfCallerIsForegroundUser())) { + (!checkIfCallerIsForegroundUser())) { Log.w(TAG,"getAddress(): not allowed for non-active and non system user"); return null; } + if (mContext.checkCallingOrSelfPermission(Manifest.permission.LOCAL_MAC_ADDRESS) + != PackageManager.PERMISSION_GRANTED) { + return BluetoothAdapter.DEFAULT_MAC_ADDRESS; + } + synchronized(mConnection) { if (mBluetooth != null) { try { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index a8ab667..2d74618 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -6164,17 +6164,6 @@ public final class ActivityManagerService extends ActivityManagerNative } } - @Override - public void systemBackupRestored() { - synchronized (this) { - if (mSystemReady) { - mTaskPersister.restoreTasksFromOtherDeviceLocked(); - } else { - Slog.w(TAG, "System backup restored before system is ready"); - } - } - } - final void ensureBootCompleted() { boolean booting; boolean enableScreen; @@ -11327,7 +11316,6 @@ public final class ActivityManagerService extends ActivityManagerNative mRecentTasks.clear(); mRecentTasks.addAll(mTaskPersister.restoreTasksLocked()); - mTaskPersister.restoreTasksFromOtherDeviceLocked(); mRecentTasks.cleanupLocked(UserHandle.USER_ALL); mTaskPersister.startPersisting(); @@ -16191,18 +16179,12 @@ public final class ActivityManagerService extends ActivityManagerNative removeUriPermissionsForPackageLocked(ssp, userId, true); removeTasksByPackageNameLocked(ssp, userId); - if (userId == UserHandle.USER_OWNER) { - mTaskPersister.removeFromPackageCache(ssp); - } mBatteryStatsService.notePackageUninstalled(ssp); } } else { cleanupDisabledPackageComponentsLocked(ssp, userId, intent.getStringArrayExtra( Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST)); - if (userId == UserHandle.USER_OWNER) { - mTaskPersister.addOtherDeviceTasksToRecentsLocked(ssp); - } } } break; @@ -16217,9 +16199,6 @@ public final class ActivityManagerService extends ActivityManagerNative intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); mCompatModePackages.handlePackageAddedLocked(ssp, replacing); - if (userId == UserHandle.USER_OWNER) { - mTaskPersister.addOtherDeviceTasksToRecentsLocked(ssp); - } try { ApplicationInfo ai = AppGlobals.getPackageManager(). getApplicationInfo(ssp, 0, 0); diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index f3b18f5..ca1fd6a 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -17,8 +17,6 @@ package com.android.server.am; import static com.android.server.am.ActivityManagerDebugConfig.*; -import static com.android.server.am.TaskPersister.DEBUG_PERSISTER; -import static com.android.server.am.TaskPersister.DEBUG_RESTORER; import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import android.app.ActivityManager.TaskDescription; @@ -85,7 +83,7 @@ final class ActivityRecord { private static final String ATTR_USERID = "user_id"; private static final String TAG_PERSISTABLEBUNDLE = "persistable_bundle"; private static final String ATTR_LAUNCHEDFROMUID = "launched_from_uid"; - static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package"; + private static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package"; private static final String ATTR_RESOLVEDTYPE = "resolved_type"; private static final String ATTR_COMPONENTSPECIFIED = "component_specified"; static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_"; @@ -94,7 +92,7 @@ final class ActivityRecord { final IApplicationToken.Stub appToken; // window manager token final ActivityInfo info; // all about me final ApplicationInfo appInfo; // information about activity's app - int launchedFromUid; // always the uid who started the activity. + final int launchedFromUid; // always the uid who started the activity. final String launchedFromPackage; // always the package who started the activity. final int userId; // Which user is this running for? final Intent intent; // the original intent that generated us @@ -1178,8 +1176,8 @@ final class ActivityRecord { } } - static ActivityRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) - throws IOException, XmlPullParserException { + static ActivityRecord restoreFromXml(XmlPullParser in, + ActivityStackSupervisor stackSupervisor) throws IOException, XmlPullParserException { Intent intent = null; PersistableBundle persistentState = null; int launchedFromUid = 0; @@ -1194,7 +1192,7 @@ final class ActivityRecord { for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { final String attrName = in.getAttributeName(attrNdx); final String attrValue = in.getAttributeValue(attrNdx); - if (DEBUG_PERSISTER || DEBUG_RESTORER) Slog.d(TaskPersister.TAG, + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "ActivityRecord: attribute name=" + attrName + " value=" + attrValue); if (ATTR_ID.equals(attrName)) { createTime = Long.valueOf(attrValue); @@ -1220,15 +1218,15 @@ final class ActivityRecord { (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) { if (event == XmlPullParser.START_TAG) { final String name = in.getName(); - if (DEBUG_PERSISTER || DEBUG_RESTORER) + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "ActivityRecord: START_TAG name=" + name); if (TAG_INTENT.equals(name)) { intent = Intent.restoreFromXml(in); - if (DEBUG_PERSISTER || DEBUG_RESTORER) + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "ActivityRecord: intent=" + intent); } else if (TAG_PERSISTABLEBUNDLE.equals(name)) { persistentState = PersistableBundle.restoreFromXml(in); - if (DEBUG_PERSISTER || DEBUG_RESTORER) Slog.d(TaskPersister.TAG, + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "ActivityRecord: persistentState=" + persistentState); } else { Slog.w(TAG, "restoreActivity: unexpected name=" + name); diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java index 318cd45..ef1559a 100644 --- a/services/core/java/com/android/server/am/TaskPersister.java +++ b/services/core/java/com/android/server/am/TaskPersister.java @@ -59,8 +59,7 @@ import static com.android.server.am.TaskRecord.INVALID_TASK_ID; public class TaskPersister { static final String TAG = "TaskPersister"; - static final boolean DEBUG_PERSISTER = false; - static final boolean DEBUG_RESTORER = false; + static final boolean DEBUG = false; /** When not flushing don't write out files faster than this */ private static final long INTER_WRITE_DELAY_MS = 500; @@ -81,21 +80,10 @@ public class TaskPersister { private static final String IMAGES_DIRNAME = "recent_images"; static final String IMAGE_EXTENSION = ".png"; - // Directory where restored historical task XML/PNG files are placed. This directory - // contains subdirs named after TASKS_DIRNAME and IMAGES_DIRNAME mirroring the - // ancestral device's dataset. This needs to match the RECENTS_TASK_RESTORE_DIR - // value in RecentsBackupHelper. - private static final String RESTORED_TASKS_DIRNAME = "restored_" + TASKS_DIRNAME; - - // Max time to wait for the application/package of a restored task to be installed - // before giving up. - private static final long MAX_INSTALL_WAIT_TIME = DateUtils.DAY_IN_MILLIS; - private static final String TAG_TASK = "task"; static File sImagesDir; static File sTasksDir; - static File sRestoredTasksDir; private final ActivityManagerService mService; private final ActivityStackSupervisor mStackSupervisor; @@ -129,23 +117,11 @@ public class TaskPersister { ArrayList<WriteQueueItem> mWriteQueue = new ArrayList<WriteQueueItem>(); - // Map of tasks that were backed-up on a different device that can be restored on this device. - // Data organization: <packageNameOfAffiliateTask, listOfAffiliatedTasksChains> - private ArrayMap<String, List<List<OtherDeviceTask>>> mOtherDeviceTasksMap = - new ArrayMap<>(10); - // Local cache of package names to uid used when restoring a task from another device. - private ArrayMap<String, Integer> mPackageUidMap; - - // The next time in milliseconds we will remove expired task from - // {@link #mOtherDeviceTasksMap} and disk. Set to {@link Long.MAX_VALUE} to never clean-up - // tasks. - private long mExpiredTasksCleanupTime = Long.MAX_VALUE; - TaskPersister(File systemDir, ActivityStackSupervisor stackSupervisor, RecentTasks recentTasks) { sTasksDir = new File(systemDir, TASKS_DIRNAME); if (!sTasksDir.exists()) { - if (DEBUG_PERSISTER) Slog.d(TAG, "Creating tasks directory " + sTasksDir); + if (DEBUG) Slog.d(TAG, "Creating tasks directory " + sTasksDir); if (!sTasksDir.mkdir()) { Slog.e(TAG, "Failure creating tasks directory " + sTasksDir); } @@ -153,14 +129,12 @@ public class TaskPersister { sImagesDir = new File(systemDir, IMAGES_DIRNAME); if (!sImagesDir.exists()) { - if (DEBUG_PERSISTER) Slog.d(TAG, "Creating images directory " + sTasksDir); + if (DEBUG) Slog.d(TAG, "Creating images directory " + sTasksDir); if (!sImagesDir.mkdir()) { Slog.e(TAG, "Failure creating images directory " + sImagesDir); } } - sRestoredTasksDir = new File(systemDir, RESTORED_TASKS_DIRNAME); - mStackSupervisor = stackSupervisor; mService = stackSupervisor.mService; mRecentTasks = recentTasks; @@ -179,8 +153,8 @@ public class TaskPersister { final WriteQueueItem item = mWriteQueue.get(queueNdx); if (item instanceof ImageWriteQueueItem && ((ImageWriteQueueItem) item).mFilename.startsWith(taskString)) { - if (DEBUG_PERSISTER) Slog.d(TAG, "Removing " - + ((ImageWriteQueueItem) item).mFilename + " from write queue"); + if (DEBUG) Slog.d(TAG, "Removing " + ((ImageWriteQueueItem) item).mFilename + + " from write queue"); mWriteQueue.remove(queueNdx); } } @@ -225,9 +199,9 @@ public class TaskPersister { } else if (mNextWriteTime == 0) { mNextWriteTime = SystemClock.uptimeMillis() + PRE_TASK_DELAY_MS; } - if (DEBUG_PERSISTER) Slog.d(TAG, "wakeup: task=" + task + " flush=" + flush - + " mNextWriteTime=" + mNextWriteTime + " mWriteQueue.size=" - + mWriteQueue.size() + " Callers=" + Debug.getCallers(4)); + if (DEBUG) Slog.d(TAG, "wakeup: task=" + task + " flush=" + flush + " mNextWriteTime=" + + mNextWriteTime + " mWriteQueue.size=" + mWriteQueue.size() + + " Callers=" + Debug.getCallers(4)); notifyAll(); } @@ -269,7 +243,7 @@ public class TaskPersister { } else if (mNextWriteTime == 0) { mNextWriteTime = SystemClock.uptimeMillis() + PRE_TASK_DELAY_MS; } - if (DEBUG_PERSISTER) Slog.d(TAG, "saveImage: filename=" + filename + " now=" + + if (DEBUG) Slog.d(TAG, "saveImage: filename=" + filename + " now=" + SystemClock.uptimeMillis() + " mNextWriteTime=" + mNextWriteTime + " Callers=" + Debug.getCallers(4)); notifyAll(); @@ -303,12 +277,12 @@ public class TaskPersister { } private StringWriter saveToXml(TaskRecord task) throws IOException, XmlPullParserException { - if (DEBUG_PERSISTER) Slog.d(TAG, "saveToXml: task=" + task); + if (DEBUG) Slog.d(TAG, "saveToXml: task=" + task); final XmlSerializer xmlSerializer = new FastXmlSerializer(); StringWriter stringWriter = new StringWriter(); xmlSerializer.setOutput(stringWriter); - if (DEBUG_PERSISTER) xmlSerializer.setFeature( + if (DEBUG) xmlSerializer.setFeature( "http://xmlpull.org/v1/doc/features.html#indent-output", true); // save task @@ -367,7 +341,7 @@ public class TaskPersister { for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) { File taskFile = recentFiles[taskNdx]; - if (DEBUG_PERSISTER) Slog.d(TAG, "restoreTasksLocked: taskFile=" + taskFile.getName()); + if (DEBUG) Slog.d(TAG, "restoreTasksLocked: taskFile=" + taskFile.getName()); BufferedReader reader = null; boolean deleteFile = false; try { @@ -380,12 +354,11 @@ public class TaskPersister { event != XmlPullParser.END_TAG) { final String name = in.getName(); if (event == XmlPullParser.START_TAG) { - if (DEBUG_PERSISTER) - Slog.d(TAG, "restoreTasksLocked: START_TAG name=" + name); + if (DEBUG) Slog.d(TAG, "restoreTasksLocked: START_TAG name=" + name); if (TAG_TASK.equals(name)) { final TaskRecord task = TaskRecord.restoreFromXml(in, mStackSupervisor); - if (DEBUG_PERSISTER) Slog.d(TAG, "restoreTasksLocked: restored task=" + + if (DEBUG) Slog.d(TAG, "restoreTasksLocked: restored task=" + task); if (task != null) { task.isPersistable = true; @@ -414,15 +387,14 @@ public class TaskPersister { deleteFile = true; } finally { IoUtils.closeQuietly(reader); - if (!DEBUG_PERSISTER && deleteFile) { - if (true || DEBUG_PERSISTER) - Slog.d(TAG, "Deleting file=" + taskFile.getName()); + if (deleteFile) { + if (DEBUG) Slog.d(TAG, "Deleting file=" + taskFile.getName()); taskFile.delete(); } } } - if (!DEBUG_PERSISTER) { + if (!DEBUG) { removeObsoleteFiles(recoveredTaskIds); } @@ -453,8 +425,8 @@ public class TaskPersister { } private static void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) { - if (DEBUG_PERSISTER) Slog.d(TAG, "removeObsoleteFile: persistentTaskIds=" - + persistentTaskIds + " files=" + files); + if (DEBUG) Slog.d(TAG, "removeObsoleteFile: persistentTaskIds=" + persistentTaskIds + + " files=" + files); if (files == null) { Slog.e(TAG, "File error accessing recents directory (too many files open?)."); return; @@ -467,15 +439,14 @@ public class TaskPersister { final int taskId; try { taskId = Integer.valueOf(filename.substring(0, taskIdEnd)); - if (DEBUG_PERSISTER) Slog.d(TAG, "removeObsoleteFile: Found taskId=" + taskId); + if (DEBUG) Slog.d(TAG, "removeObsoleteFile: Found taskId=" + taskId); } catch (Exception e) { Slog.wtf(TAG, "removeObsoleteFile: Can't parse file=" + file.getName()); file.delete(); continue; } if (!persistentTaskIds.contains(taskId)) { - if (true || DEBUG_PERSISTER) Slog.d(TAG, "removeObsoleteFile: deleting file=" + - file.getName()); + if (DEBUG) Slog.d(TAG, "removeObsoleteFile: deleting file=" + file.getName()); file.delete(); } } @@ -488,441 +459,10 @@ public class TaskPersister { } static Bitmap restoreImage(String filename) { - if (DEBUG_PERSISTER) Slog.d(TAG, "restoreImage: restoring " + filename); + if (DEBUG) Slog.d(TAG, "restoreImage: restoring " + filename); return BitmapFactory.decodeFile(sImagesDir + File.separator + filename); } - /** - * Tries to restore task that were backed-up on a different device onto this device. - */ - void restoreTasksFromOtherDeviceLocked() { - readOtherDeviceTasksFromDisk(); - addOtherDeviceTasksToRecentsLocked(); - } - - /** - * Read the tasks that were backed-up on a different device and can be restored to this device - * from disk and populated {@link #mOtherDeviceTasksMap} with the information. Also sets up - * time to clear out other device tasks that have not been restored on this device - * within the allotted time. - */ - private void readOtherDeviceTasksFromDisk() { - synchronized (mOtherDeviceTasksMap) { - // Clear out current map and expiration time. - mOtherDeviceTasksMap.clear(); - mExpiredTasksCleanupTime = Long.MAX_VALUE; - - final File[] taskFiles; - if (!sRestoredTasksDir.exists() - || (taskFiles = sRestoredTasksDir.listFiles()) == null) { - // Nothing to do if there are no tasks to restore. - return; - } - - long earliestMtime = System.currentTimeMillis(); - SparseArray<List<OtherDeviceTask>> tasksByAffiliateIds = - new SparseArray<>(taskFiles.length); - - // Read new tasks from disk - for (int i = 0; i < taskFiles.length; ++i) { - final File taskFile = taskFiles[i]; - if (DEBUG_RESTORER) Slog.d(TAG, "readOtherDeviceTasksFromDisk: taskFile=" - + taskFile.getName()); - - final OtherDeviceTask task = OtherDeviceTask.createFromFile(taskFile); - - if (task == null) { - // Go ahead and remove the file on disk if we are unable to create a task from - // it. - if (DEBUG_RESTORER) Slog.e(TAG, "Unable to create task for file=" - + taskFile.getName() + "...deleting file."); - taskFile.delete(); - continue; - } - - List<OtherDeviceTask> tasks = tasksByAffiliateIds.get(task.mAffiliatedTaskId); - if (tasks == null) { - tasks = new ArrayList<>(); - tasksByAffiliateIds.put(task.mAffiliatedTaskId, tasks); - } - tasks.add(task); - final long taskMtime = taskFile.lastModified(); - if (earliestMtime > taskMtime) { - earliestMtime = taskMtime; - } - } - - if (tasksByAffiliateIds.size() > 0) { - // Sort each affiliated tasks chain by taskId which is the order they were created - // that should always be correct...Then add to task map. - for (int i = 0; i < tasksByAffiliateIds.size(); i++) { - List<OtherDeviceTask> chain = tasksByAffiliateIds.valueAt(i); - Collections.sort(chain); - // Package name of the root task in the affiliate chain. - final String packageName = - chain.get(chain.size()-1).mComponentName.getPackageName(); - List<List<OtherDeviceTask>> chains = mOtherDeviceTasksMap.get(packageName); - if (chains == null) { - chains = new ArrayList<>(); - mOtherDeviceTasksMap.put(packageName, chains); - } - chains.add(chain); - } - - // Set expiration time. - mExpiredTasksCleanupTime = earliestMtime + MAX_INSTALL_WAIT_TIME; - if (DEBUG_RESTORER) Slog.d(TAG, "Set Expiration time to " - + DateUtils.formatDateTime(mService.mContext, mExpiredTasksCleanupTime, - DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME)); - } - } - } - - /** - * Removed any expired tasks from {@link #mOtherDeviceTasksMap} and disk if their expiration - * time is less than or equal to {@link #mExpiredTasksCleanupTime}. - */ - private void removeExpiredTasksIfNeeded() { - synchronized (mOtherDeviceTasksMap) { - final long now = System.currentTimeMillis(); - final boolean noMoreTasks = mOtherDeviceTasksMap.isEmpty(); - if (noMoreTasks || now < mExpiredTasksCleanupTime) { - if (noMoreTasks && mPackageUidMap != null) { - // All done! package->uid map no longer needed. - mPackageUidMap = null; - } - return; - } - - long earliestNonExpiredMtime = now; - mExpiredTasksCleanupTime = Long.MAX_VALUE; - - // Remove expired backed-up tasks that have not been restored. We only want to - // remove task if it is safe to remove all tasks in the affiliation chain. - for (int i = mOtherDeviceTasksMap.size() - 1; i >= 0 ; i--) { - - List<List<OtherDeviceTask>> chains = mOtherDeviceTasksMap.valueAt(i); - for (int j = chains.size() - 1; j >= 0 ; j--) { - - List<OtherDeviceTask> chain = chains.get(j); - boolean removeChain = true; - for (int k = chain.size() - 1; k >= 0 ; k--) { - OtherDeviceTask task = chain.get(k); - final long taskLastModified = task.mFile.lastModified(); - if ((taskLastModified + MAX_INSTALL_WAIT_TIME) > now) { - // File has not expired yet...but we keep looping to get the earliest - // mtime. - if (earliestNonExpiredMtime > taskLastModified) { - earliestNonExpiredMtime = taskLastModified; - } - removeChain = false; - } - } - if (removeChain) { - for (int k = chain.size() - 1; k >= 0; k--) { - final File file = chain.get(k).mFile; - if (DEBUG_RESTORER) Slog.d(TAG, "Deleting expired file=" - + file.getName() + " mapped to not installed component=" - + chain.get(k).mComponentName); - file.delete(); - } - chains.remove(j); - } - } - if (chains.isEmpty()) { - final String packageName = mOtherDeviceTasksMap.keyAt(i); - mOtherDeviceTasksMap.removeAt(i); - if (DEBUG_RESTORER) Slog.d(TAG, "Removed package=" + packageName - + " from task map"); - } - } - - // Reset expiration time if there is any task remaining. - if (!mOtherDeviceTasksMap.isEmpty()) { - mExpiredTasksCleanupTime = earliestNonExpiredMtime + MAX_INSTALL_WAIT_TIME; - if (DEBUG_RESTORER) Slog.d(TAG, "Reset expiration time to " - + DateUtils.formatDateTime(mService.mContext, mExpiredTasksCleanupTime, - DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME)); - } else { - // All done! package->uid map no longer needed. - mPackageUidMap = null; - } - } - } - - /** - * Removes the input package name from the local package->uid map. - */ - void removeFromPackageCache(String packageName) { - synchronized (mOtherDeviceTasksMap) { - if (mPackageUidMap != null) { - mPackageUidMap.remove(packageName); - } - } - } - - /** - * Tries to add all backed-up tasks from another device to this device recent's list. - */ - private void addOtherDeviceTasksToRecentsLocked() { - synchronized (mOtherDeviceTasksMap) { - for (int i = mOtherDeviceTasksMap.size() - 1; i >= 0; i--) { - addOtherDeviceTasksToRecentsLocked(mOtherDeviceTasksMap.keyAt(i)); - } - } - } - - /** - * Tries to add backed-up tasks that are associated with the input package from - * another device to this device recent's list. - */ - void addOtherDeviceTasksToRecentsLocked(String packageName) { - synchronized (mOtherDeviceTasksMap) { - List<List<OtherDeviceTask>> chains = mOtherDeviceTasksMap.get(packageName); - if (chains == null) { - return; - } - - for (int i = chains.size() - 1; i >= 0; i--) { - List<OtherDeviceTask> chain = chains.get(i); - if (!canAddOtherDeviceTaskChain(chain)) { - if (DEBUG_RESTORER) Slog.d(TAG, "Can't add task chain at index=" + i - + " for package=" + packageName); - continue; - } - - // Generate task records for this chain. - List<TaskRecord> tasks = new ArrayList<>(); - TaskRecord prev = null; - for (int j = chain.size() - 1; j >= 0; j--) { - TaskRecord task = createTaskRecordLocked(chain.get(j)); - if (task == null) { - // There was a problem in creating one of this task records in this chain. - // There is no way we can continue... - if (DEBUG_RESTORER) Slog.d(TAG, "Can't create task record for file=" - + chain.get(j).mFile + " for package=" + packageName); - break; - } - - // Wire-up affiliation chain. - if (prev == null) { - task.mPrevAffiliate = null; - task.mPrevAffiliateTaskId = INVALID_TASK_ID; - task.mAffiliatedTaskId = task.taskId; - } else { - prev.mNextAffiliate = task; - prev.mNextAffiliateTaskId = task.taskId; - task.mAffiliatedTaskId = prev.mAffiliatedTaskId; - task.mPrevAffiliate = prev; - task.mPrevAffiliateTaskId = prev.taskId; - } - prev = task; - tasks.add(0, task); - } - - // Add tasks to recent's if we were able to create task records for all the tasks - // in the chain. - if (tasks.size() == chain.size()) { - // Make sure there is space in recent's to add the new task. If there is space - // to the to the back. - // TODO: Would be more fancy to interleave the new tasks into recent's based on - // {@link TaskRecord.mLastTimeMoved} and drop the oldest recent's vs. just - // adding to the back of the list. - int spaceLeft = - ActivityManager.getMaxRecentTasksStatic() - mRecentTasks.size(); - if (spaceLeft >= tasks.size()) { - mRecentTasks.addAll(mRecentTasks.size(), tasks); - for (int k = tasks.size() - 1; k >= 0; k--) { - // Persist new tasks. - wakeup(tasks.get(k), false); - } - - if (DEBUG_RESTORER) Slog.d(TAG, "Added " + tasks.size() - + " tasks to recent's for" + " package=" + packageName); - } else { - if (DEBUG_RESTORER) Slog.d(TAG, "Didn't add to recents. tasks.size(" - + tasks.size() + ") != chain.size(" + chain.size() - + ") for package=" + packageName); - } - } else { - if (DEBUG_RESTORER) Slog.v(TAG, "Unable to add restored tasks to recents " - + tasks.size() + " tasks for package=" + packageName); - } - - // Clean-up structures - for (int j = chain.size() - 1; j >= 0; j--) { - chain.get(j).mFile.delete(); - } - chains.remove(i); - if (chains.isEmpty()) { - // The fate of all backed-up tasks associated with this package has been - // determine. Go ahead and remove it from the to-process list. - mOtherDeviceTasksMap.remove(packageName); - if (DEBUG_RESTORER) - Slog.d(TAG, "Removed package=" + packageName + " from restore map"); - } - } - } - } - - /** - * Creates and returns {@link TaskRecord} for the task from another device that can be used on - * this device. Returns null if the operation failed. - */ - private TaskRecord createTaskRecordLocked(OtherDeviceTask other) { - File file = other.mFile; - BufferedReader reader = null; - TaskRecord task = null; - if (DEBUG_RESTORER) Slog.d(TAG, "createTaskRecordLocked: file=" + file.getName()); - - try { - reader = new BufferedReader(new FileReader(file)); - final XmlPullParser in = Xml.newPullParser(); - in.setInput(reader); - - int event; - while (((event = in.next()) != XmlPullParser.END_DOCUMENT) - && event != XmlPullParser.END_TAG) { - final String name = in.getName(); - if (event == XmlPullParser.START_TAG) { - - if (TAG_TASK.equals(name)) { - // Create a task record using a task id that is valid for this device. - task = TaskRecord.restoreFromXml( - in, mStackSupervisor, mStackSupervisor.getNextTaskId()); - if (DEBUG_RESTORER) - Slog.d(TAG, "createTaskRecordLocked: restored task=" + task); - - if (task != null) { - task.isPersistable = true; - task.inRecents = true; - // Task can/should only be backed-up/restored for device owner. - task.userId = UserHandle.USER_OWNER; - // Clear out affiliated ids that are no longer valid on this device. - task.mAffiliatedTaskId = INVALID_TASK_ID; - task.mPrevAffiliateTaskId = INVALID_TASK_ID; - task.mNextAffiliateTaskId = INVALID_TASK_ID; - // Set up uids valid for this device. - Integer uid = mPackageUidMap.get(task.realActivity.getPackageName()); - if (uid == null) { - // How did this happen??? - Slog.wtf(TAG, "Can't find uid for task=" + task - + " in mPackageUidMap=" + mPackageUidMap); - return null; - } - task.effectiveUid = task.mCallingUid = uid; - for (int i = task.mActivities.size() - 1; i >= 0; --i) { - final ActivityRecord activity = task.mActivities.get(i); - uid = mPackageUidMap.get(activity.launchedFromPackage); - if (uid == null) { - // How did this happen?? - Slog.wtf(TAG, "Can't find uid for activity=" + activity - + " in mPackageUidMap=" + mPackageUidMap); - return null; - } - activity.launchedFromUid = uid; - } - - } else { - Slog.e(TAG, "Unable to create task for backed-up file=" + file + ": " - + fileToString(file)); - } - } else { - Slog.wtf(TAG, "createTaskRecordLocked Unknown xml event=" + event - + " name=" + name); - } - } - XmlUtils.skipCurrentTag(in); - } - } catch (Exception e) { - Slog.wtf(TAG, "Unable to parse " + file + ". Error ", e); - Slog.e(TAG, "Failing file: " + fileToString(file)); - } finally { - IoUtils.closeQuietly(reader); - } - - return task; - } - - /** - * Returns true if the input task chain backed-up from another device can be restored on this - * device. Also, sets the {@link OtherDeviceTask#mUid} on the input tasks if they can be - * restored. - */ - private boolean canAddOtherDeviceTaskChain(List<OtherDeviceTask> chain) { - - final ArraySet<ComponentName> validComponents = new ArraySet<>(); - final IPackageManager pm = AppGlobals.getPackageManager(); - for (int i = 0; i < chain.size(); i++) { - - OtherDeviceTask task = chain.get(i); - // Quick check, we can't add the task chain if any of its task files don't exist. - if (!task.mFile.exists()) { - if (DEBUG_RESTORER) Slog.d(TAG, - "Can't add chain due to missing file=" + task.mFile); - return false; - } - - // Verify task package is installed. - if (!isPackageInstalled(task.mComponentName.getPackageName())) { - return false; - } - // Verify that all the launch packages are installed. - if (task.mLaunchPackages != null) { - for (int j = task.mLaunchPackages.size() - 1; j >= 0; --j) { - if (!isPackageInstalled(task.mLaunchPackages.valueAt(j))) { - return false; - } - } - } - - if (validComponents.contains(task.mComponentName)) { - // Existance of component has already been verified. - continue; - } - - // Check to see if the specific component is installed. - try { - if (pm.getActivityInfo(task.mComponentName, 0, UserHandle.USER_OWNER) == null) { - // Component isn't installed... - return false; - } - validComponents.add(task.mComponentName); - } catch (RemoteException e) { - // Should not happen??? - return false; - } - } - - return true; - } - - /** - * Returns true if the input package name is installed. If the package is installed, an entry - * for the package is added to {@link #mPackageUidMap}. - */ - private boolean isPackageInstalled(final String packageName) { - if (mPackageUidMap != null && mPackageUidMap.containsKey(packageName)) { - return true; - } - try { - int uid = AppGlobals.getPackageManager().getPackageUid( - packageName, UserHandle.USER_OWNER); - if (uid == -1) { - // package doesn't exist... - return false; - } - if (mPackageUidMap == null) { - mPackageUidMap = new ArrayMap<>(); - } - mPackageUidMap.put(packageName, uid); - return true; - } catch (RemoteException e) { - // Should not happen??? - return false; - } - } - private class LazyTaskWriterThread extends Thread { LazyTaskWriterThread(String name) { @@ -941,21 +481,20 @@ public class TaskPersister { probablyDone = mWriteQueue.isEmpty(); } if (probablyDone) { - if (DEBUG_PERSISTER) Slog.d(TAG, "Looking for obsolete files."); + if (DEBUG) Slog.d(TAG, "Looking for obsolete files."); persistentTaskIds.clear(); synchronized (mService) { - if (DEBUG_PERSISTER) Slog.d(TAG, "mRecents=" + mRecentTasks); + if (DEBUG) Slog.d(TAG, "mRecents=" + mRecentTasks); for (int taskNdx = mRecentTasks.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord task = mRecentTasks.get(taskNdx); - if (DEBUG_PERSISTER) Slog.d(TAG, "LazyTaskWriter: task=" + task + + if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + " persistable=" + task.isPersistable); if ((task.isPersistable || task.inRecents) && (task.stack == null || !task.stack.isHomeStack())) { - if (DEBUG_PERSISTER) - Slog.d(TAG, "adding to persistentTaskIds task=" + task); + if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task); persistentTaskIds.add(task.taskId); } else { - if (DEBUG_PERSISTER) Slog.d(TAG, + if (DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task=" + task); } } @@ -969,7 +508,7 @@ public class TaskPersister { if (mNextWriteTime != FLUSH_QUEUE) { // The next write we don't have to wait so long. mNextWriteTime = SystemClock.uptimeMillis() + INTER_WRITE_DELAY_MS; - if (DEBUG_PERSISTER) Slog.d(TAG, "Next write time may be in " + + if (DEBUG) Slog.d(TAG, "Next write time may be in " + INTER_WRITE_DELAY_MS + " msec. (" + mNextWriteTime + ")"); } @@ -979,13 +518,8 @@ public class TaskPersister { mNextWriteTime = 0; // idle. TaskPersister.this.notifyAll(); // wake up flush() if needed. } - - // See if we need to remove any expired back-up tasks before waiting. - removeExpiredTasksIfNeeded(); - try { - if (DEBUG_PERSISTER) - Slog.d(TAG, "LazyTaskWriter: waiting indefinitely."); + if (DEBUG) Slog.d(TAG, "LazyTaskWriter: waiting indefinitely."); TaskPersister.this.wait(); } catch (InterruptedException e) { } @@ -995,12 +529,11 @@ public class TaskPersister { item = mWriteQueue.remove(0); long now = SystemClock.uptimeMillis(); - if (DEBUG_PERSISTER) Slog.d(TAG, "LazyTaskWriter: now=" + now - + " mNextWriteTime=" + mNextWriteTime + " mWriteQueue.size=" - + mWriteQueue.size()); + if (DEBUG) Slog.d(TAG, "LazyTaskWriter: now=" + now + " mNextWriteTime=" + + mNextWriteTime + " mWriteQueue.size=" + mWriteQueue.size()); while (now < mNextWriteTime) { try { - if (DEBUG_PERSISTER) Slog.d(TAG, "LazyTaskWriter: waiting " + + if (DEBUG) Slog.d(TAG, "LazyTaskWriter: waiting " + (mNextWriteTime - now)); TaskPersister.this.wait(mNextWriteTime - now); } catch (InterruptedException e) { @@ -1015,7 +548,7 @@ public class TaskPersister { ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item; final String filename = imageWriteQueueItem.mFilename; final Bitmap bitmap = imageWriteQueueItem.mImage; - if (DEBUG_PERSISTER) Slog.d(TAG, "writing bitmap: filename=" + filename); + if (DEBUG) Slog.d(TAG, "writing bitmap: filename=" + filename); FileOutputStream imageFile = null; try { imageFile = new FileOutputStream(new File(sImagesDir, filename)); @@ -1029,12 +562,12 @@ public class TaskPersister { // Write out one task. StringWriter stringWriter = null; TaskRecord task = ((TaskWriteQueueItem) item).mTask; - if (DEBUG_PERSISTER) Slog.d(TAG, "Writing task=" + task); + if (DEBUG) Slog.d(TAG, "Writing task=" + task); synchronized (mService) { if (task.inRecents) { // Still there. try { - if (DEBUG_PERSISTER) Slog.d(TAG, "Saving task=" + task); + if (DEBUG) Slog.d(TAG, "Saving task=" + task); stringWriter = saveToXml(task); } catch (IOException e) { } catch (XmlPullParserException e) { @@ -1064,127 +597,4 @@ public class TaskPersister { } } } - - /** - * Helper class for holding essential information about task that were backed-up on a different - * device that can be restored on this device. - */ - private static class OtherDeviceTask implements Comparable<OtherDeviceTask> { - final File mFile; - // See {@link TaskRecord} for information on the fields below. - final ComponentName mComponentName; - final int mTaskId; - final int mAffiliatedTaskId; - - // Names of packages that launched activities in this task. All packages listed here need - // to be installed on the current device in order for the task to be restored successfully. - final ArraySet<String> mLaunchPackages; - - private OtherDeviceTask(File file, ComponentName componentName, int taskId, - int affiliatedTaskId, ArraySet<String> launchPackages) { - mFile = file; - mComponentName = componentName; - mTaskId = taskId; - mAffiliatedTaskId = (affiliatedTaskId == INVALID_TASK_ID) ? taskId: affiliatedTaskId; - mLaunchPackages = launchPackages; - } - - @Override - public int compareTo(OtherDeviceTask another) { - return mTaskId - another.mTaskId; - } - - /** - * Creates a new {@link OtherDeviceTask} object based on the contents of the input file. - * - * @param file input file that contains the complete task information. - * @return new {@link OtherDeviceTask} object or null if we failed to create the object. - */ - static OtherDeviceTask createFromFile(File file) { - if (file == null || !file.exists()) { - if (DEBUG_RESTORER) - Slog.d(TAG, "createFromFile: file=" + file + " doesn't exist."); - return null; - } - - BufferedReader reader = null; - - try { - reader = new BufferedReader(new FileReader(file)); - final XmlPullParser in = Xml.newPullParser(); - in.setInput(reader); - - int event; - while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && - event != XmlPullParser.START_TAG) { - // Skip to the start tag or end of document - } - - if (event == XmlPullParser.START_TAG) { - final String name = in.getName(); - - if (TAG_TASK.equals(name)) { - final int outerDepth = in.getDepth(); - ComponentName componentName = null; - int taskId = INVALID_TASK_ID; - int taskAffiliation = INVALID_TASK_ID; - for (int j = in.getAttributeCount() - 1; j >= 0; --j) { - final String attrName = in.getAttributeName(j); - final String attrValue = in.getAttributeValue(j); - if (TaskRecord.ATTR_REALACTIVITY.equals(attrName)) { - componentName = ComponentName.unflattenFromString(attrValue); - } else if (TaskRecord.ATTR_TASKID.equals(attrName)) { - taskId = Integer.valueOf(attrValue); - } else if (TaskRecord.ATTR_TASK_AFFILIATION.equals(attrName)) { - taskAffiliation = Integer.valueOf(attrValue); - } - } - if (componentName == null || taskId == INVALID_TASK_ID) { - if (DEBUG_RESTORER) Slog.e(TAG, - "createFromFile: FAILED componentName=" + componentName - + " taskId=" + taskId + " file=" + file); - return null; - } - - ArraySet<String> launchPackages = null; - while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && - (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) { - if (event == XmlPullParser.START_TAG) { - if (TaskRecord.TAG_ACTIVITY.equals(in.getName())) { - for (int j = in.getAttributeCount() - 1; j >= 0; --j) { - if (ActivityRecord.ATTR_LAUNCHEDFROMPACKAGE.equals( - in.getAttributeName(j))) { - if (launchPackages == null) { - launchPackages = new ArraySet(); - } - launchPackages.add(in.getAttributeValue(j)); - } - } - } else { - XmlUtils.skipCurrentTag(in); - } - } - } - if (DEBUG_RESTORER) Slog.d(TAG, "creating OtherDeviceTask from file=" - + file.getName() + " componentName=" + componentName - + " taskId=" + taskId + " launchPackages=" + launchPackages); - return new OtherDeviceTask(file, componentName, taskId, - taskAffiliation, launchPackages); - } else { - Slog.wtf(TAG, - "createFromFile: Unknown xml event=" + event + " name=" + name); - } - } else { - Slog.wtf(TAG, "createFromFile: Unable to find start tag in file=" + file); - } - } catch (IOException | XmlPullParserException e) { - Slog.wtf(TAG, "Unable to parse " + file + ". Error ", e); - } finally { - IoUtils.closeQuietly(reader); - } - - // Something went wrong... - return null; - } - } } diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index f653e9e..417c7c3 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -28,8 +28,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.TaskPersister.DEBUG_PERSISTER; -import static com.android.server.am.TaskPersister.DEBUG_RESTORER; import android.app.Activity; import android.app.ActivityManager; @@ -71,7 +69,7 @@ final class TaskRecord { private static final String TAG_AFFINITYINTENT = "affinity_intent"; static final String ATTR_REALACTIVITY = "real_activity"; private static final String ATTR_ORIGACTIVITY = "orig_activity"; - static final String TAG_ACTIVITY = "activity"; + private static final String TAG_ACTIVITY = "activity"; private static final String ATTR_AFFINITY = "affinity"; private static final String ATTR_ROOT_AFFINITY = "root_affinity"; private static final String ATTR_ROOTHASRESET = "root_has_reset"; @@ -970,10 +968,6 @@ final class TaskRecord { static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) throws IOException, XmlPullParserException { - return restoreFromXml(in, stackSupervisor, INVALID_TASK_ID); - } - static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor, - int inTaskId) throws IOException, XmlPullParserException { Intent intent = null; Intent affinityIntent = null; ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>(); @@ -993,7 +987,7 @@ final class TaskRecord { long lastActiveTime = -1; long lastTimeOnTop = 0; boolean neverRelinquishIdentity = true; - int taskId = inTaskId; + int taskId = INVALID_TASK_ID; final int outerDepth = in.getDepth(); TaskDescription taskDescription = new TaskDescription(); int taskAffiliation = INVALID_TASK_ID; @@ -1008,8 +1002,8 @@ final class TaskRecord { for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { final String attrName = in.getAttributeName(attrNdx); final String attrValue = in.getAttributeValue(attrNdx); - if (DEBUG_PERSISTER || DEBUG_RESTORER) Slog.d(TaskPersister.TAG, - "TaskRecord: attribute name=" + attrName + " value=" + attrValue); + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" + + attrName + " value=" + attrValue); if (ATTR_TASKID.equals(attrName)) { if (taskId == INVALID_TASK_ID) taskId = Integer.valueOf(attrValue); } else if (ATTR_REALACTIVITY.equals(attrName)) { @@ -1071,16 +1065,16 @@ final class TaskRecord { (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) { if (event == XmlPullParser.START_TAG) { final String name = in.getName(); - if (DEBUG_PERSISTER || DEBUG_RESTORER) - Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" + name); + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" + + name); if (TAG_AFFINITYINTENT.equals(name)) { affinityIntent = Intent.restoreFromXml(in); } else if (TAG_INTENT.equals(name)) { intent = Intent.restoreFromXml(in); } else if (TAG_ACTIVITY.equals(name)) { ActivityRecord activity = ActivityRecord.restoreFromXml(in, stackSupervisor); - if (DEBUG_PERSISTER || DEBUG_RESTORER) - Slog.d(TaskPersister.TAG, "TaskRecord: activity=" + activity); + if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" + + activity); if (activity != null) { activities.add(activity); } diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index 75198e5..dbfd4ef 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -42,6 +42,14 @@ public class WifiInfo implements Parcelable { private static final EnumMap<SupplicantState, DetailedState> stateMap = new EnumMap<SupplicantState, DetailedState>(SupplicantState.class); + /** + * Default MAC address reported to a client that does not have the + * android.permission.LOCAL_MAC_ADDRESS permission. + * + * @hide + */ + public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; + static { stateMap.put(SupplicantState.DISCONNECTED, DetailedState.DISCONNECTED); stateMap.put(SupplicantState.INTERFACE_DISABLED, DetailedState.DISCONNECTED); @@ -91,7 +99,7 @@ public class WifiInfo implements Parcelable { private int mFrequency; private InetAddress mIpAddress; - private String mMacAddress; + private String mMacAddress = DEFAULT_MAC_ADDRESS; /** * @hide |
