diff options
69 files changed, 605 insertions, 167 deletions
diff --git a/api/current.txt b/api/current.txt index 05e494b3c22f..e295a630d36c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3412,6 +3412,7 @@ package android.app { method public boolean onSearchRequested(android.view.SearchEvent); method public boolean onSearchRequested(); method protected void onStart(); + method public void onStateNotSaved(); method protected void onStop(); method protected void onTitleChanged(java.lang.CharSequence, int); method public boolean onTouchEvent(android.view.MotionEvent); @@ -35139,6 +35140,10 @@ package android.view { field public static final int KEYCODE_MEDIA_PREVIOUS = 88; // 0x58 field public static final int KEYCODE_MEDIA_RECORD = 130; // 0x82 field public static final int KEYCODE_MEDIA_REWIND = 89; // 0x59 + field public static final int KEYCODE_MEDIA_SKIP_BACKWARD = 273; // 0x111 + field public static final int KEYCODE_MEDIA_SKIP_FORWARD = 272; // 0x110 + field public static final int KEYCODE_MEDIA_STEP_BACKWARD = 275; // 0x113 + field public static final int KEYCODE_MEDIA_STEP_FORWARD = 274; // 0x112 field public static final int KEYCODE_MEDIA_STOP = 86; // 0x56 field public static final int KEYCODE_MEDIA_TOP_MENU = 226; // 0xe2 field public static final int KEYCODE_MENU = 82; // 0x52 diff --git a/api/system-current.txt b/api/system-current.txt index d9702acf4069..8b9af5e9b084 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -115,7 +115,6 @@ package android { field public static final java.lang.String INTERNET = "android.permission.INTERNET"; 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"; @@ -3516,6 +3515,7 @@ package android.app { method public boolean onSearchRequested(android.view.SearchEvent); method public boolean onSearchRequested(); method protected void onStart(); + method public void onStateNotSaved(); method protected void onStop(); method protected void onTitleChanged(java.lang.CharSequence, int); method public boolean onTouchEvent(android.view.MotionEvent); @@ -3653,7 +3653,6 @@ package android.app { method public static boolean isRunningInTestHarness(); method public static boolean isUserAMonkey(); method public void killBackgroundProcesses(java.lang.String); - method public void killUid(int, java.lang.String); method public void moveTaskToFront(int, int); method public void moveTaskToFront(int, int, android.os.Bundle); method public deprecated void restartPackage(java.lang.String); @@ -37433,6 +37432,10 @@ package android.view { field public static final int KEYCODE_MEDIA_PREVIOUS = 88; // 0x58 field public static final int KEYCODE_MEDIA_RECORD = 130; // 0x82 field public static final int KEYCODE_MEDIA_REWIND = 89; // 0x59 + field public static final int KEYCODE_MEDIA_SKIP_BACKWARD = 273; // 0x111 + field public static final int KEYCODE_MEDIA_SKIP_FORWARD = 272; // 0x110 + field public static final int KEYCODE_MEDIA_STEP_BACKWARD = 275; // 0x113 + field public static final int KEYCODE_MEDIA_STEP_FORWARD = 274; // 0x112 field public static final int KEYCODE_MEDIA_STOP = 86; // 0x56 field public static final int KEYCODE_MEDIA_TOP_MENU = 226; // 0xe2 field public static final int KEYCODE_MENU = 82; // 0x52 diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 3c8af0d5444a..2cb3f397718d 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1172,6 +1172,16 @@ public class Activity extends ContextThemeWrapper } /** + * Called when an {@link #onResume} is coming up, prior to other pre-resume callbacks + * such as {@link #onNewIntent} and {@link #onActivityResult}. This is primarily intended + * to give the activity a hint that its state is no longer saved -- it will generally + * be called after {@link #onSaveInstanceState} and prior to the activity being + * resumed/started again. + */ + public void onStateNotSaved() { + } + + /** * Called after {@link #onRestoreInstanceState}, {@link #onRestart}, or * {@link #onPause}, for your activity to start interacting with the user. * This is a good place to begin animations, open exclusive-access devices diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 55b2fd92c824..87c9efc2e104 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2430,11 +2430,11 @@ public class ActivityManager { * * @hide */ - @SystemApi @RequiresPermission(Manifest.permission.KILL_UID) public void killUid(int uid, String reason) { try { - ActivityManagerNative.getDefault().killUid(uid, reason); + ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid), + UserHandle.getUserId(uid), reason); } catch (RemoteException e) { Log.e(TAG, "Couldn't kill uid:" + uid, e); } diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index e144c297f50e..f6e0735a2b0f 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2245,9 +2245,10 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case KILL_UID_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); - int uid = data.readInt(); + int appId = data.readInt(); + int userId = data.readInt(); String reason = data.readString(); - killUid(uid, reason); + killUid(appId, userId, reason); reply.writeNoException(); return true; } @@ -5479,11 +5480,12 @@ class ActivityManagerProxy implements IActivityManager return res; } - public void killUid(int uid, String reason) throws RemoteException { + public void killUid(int appId, int userId, String reason) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); - data.writeInt(uid); + data.writeInt(appId); + data.writeInt(userId); data.writeString(reason); mRemote.transact(KILL_UID_TRANSACTION, data, reply, 0); reply.readException(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 2b4d03b41fb9..fd88a0549a10 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3079,6 +3079,7 @@ public final class ActivityThread { r.activity.mStartedActivity = false; } try { + r.activity.onStateNotSaved(); r.activity.mFragments.noteStateNotSaved(); if (r.pendingIntents != null) { deliverNewIntents(r, r.pendingIntents); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 90216af3745c..ef121ce2d806 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -447,7 +447,7 @@ public interface IActivityManager extends IInterface { public boolean showAssistFromActivity(IBinder token, Bundle args) throws RemoteException; - public void killUid(int uid, String reason) throws RemoteException; + public void killUid(int appId, int userId, String reason) throws RemoteException; public void hang(IBinder who, boolean allowRestart) throws RemoteException; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 2d729c7d71fe..c505b0bfc6b0 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -124,6 +124,12 @@ public class DevicePolicyManager { * * <p> If provisioning fails, the managedProfile is removed so the device returns to its * previous state. + * + * <p>If launched with {@link android.app.Activity#startActivityForResult(Intent, int)} a + * result code of {@link android.app.Activity#RESULT_OK} implies that the synchronous part of + * the provisioning flow was successful, although this doesn't guarantee the full flow will + * succeed. Conversely a result code of {@link android.app.Activity#RESULT_CANCELED} implies + * that the user backed-out of provisioning, or some precondition for provisioning wasn't met. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_PROVISION_MANAGED_PROFILE @@ -158,6 +164,10 @@ public class DevicePolicyManager { * * <p> If provisioning fails, the device is factory reset. * + * <p>A result code of {@link android.app.Activity#RESULT_OK} implies that the synchronous part + * of the provisioning flow was successful, although this doesn't guarantee the full flow will + * succeed. Conversely a result code of {@link android.app.Activity#RESULT_CANCELED} implies + * that the user backed-out of provisioning, or some precondition for provisioning wasn't met. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_PROVISION_MANAGED_DEVICE diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index aa4b0514c02d..64877aa69c4d 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -27,6 +27,12 @@ import android.os.ParcelFileDescriptor; * {@hide} */ interface IUserManager { + + /* + * DO NOT MOVE - UserManager.h depends on the ordering of this function. + */ + int getCredentialOwnerProfile(int userHandle); + UserInfo createUser(in String name, int flags); UserInfo createProfileForUser(in String name, int flags, int userHandle); void setUserEnabled(int userHandle); diff --git a/core/java/android/os/NullVibrator.java b/core/java/android/os/NullVibrator.java index f14d96512cef..19b452f323ce 100644 --- a/core/java/android/os/NullVibrator.java +++ b/core/java/android/os/NullVibrator.java @@ -43,7 +43,6 @@ public class NullVibrator extends Vibrator { */ @Override public void vibrate(int uid, String opPkg, long milliseconds, AudioAttributes attributes) { - vibrate(milliseconds); } /** diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 83a1993775de..045c1e88ec01 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1068,6 +1068,22 @@ public class UserManager { } /** + * Returns the device credential owner id of the profile from + * which this method is called, or userHandle if called from a user that + * is not a profile. + * + * @hide + */ + public int getCredentialOwnerProfile(int userHandle) { + try { + return mService.getCredentialOwnerProfile(userHandle); + } catch (RemoteException re) { + Log.w(TAG, "Could not get credential owner", re); + return -1; + } + } + + /** * Returns the parent of the profile which this method is called from * or null if called from a user that is not a profile. * diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 6f98788976bf..bb09b05ffdd2 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7554,6 +7554,13 @@ public final class Settings { } /** + * Value of the ringer before entering zen mode. + * + * @hide + */ + public static final String ZEN_MODE_RINGER_LEVEL = "zen_mode_ringer_level"; + + /** * Opaque value, changes when persisted zen mode configuration changes. * * @hide diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index f6ce353906cd..a9bf92b1dfa3 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -747,22 +747,32 @@ public class KeyEvent extends InputEvent implements Parcelable { public static final int KEYCODE_TV_TIMER_PROGRAMMING = 258; /** Key code constant: Help key. */ public static final int KEYCODE_HELP = 259; - /** Key code constant: Navigate to previous key. + /** Key code constant: Navigate to previous key. * Goes backward by one item in an ordered collection of items. */ public static final int KEYCODE_NAVIGATE_PREVIOUS = 260; - /** Key code constant: Navigate to next key. + /** Key code constant: Navigate to next key. * Advances to the next item in an ordered collection of items. */ public static final int KEYCODE_NAVIGATE_NEXT = 261; /** Key code constant: Navigate in key. - * Activates the item that currently has focus or expands to the next level of a navigation + * Activates the item that currently has focus or expands to the next level of a navigation * hierarchy. */ public static final int KEYCODE_NAVIGATE_IN = 262; /** Key code constant: Navigate out key. - * Backs out one level of a navigation hierarchy or collapses the item that currently has + * Backs out one level of a navigation hierarchy or collapses the item that currently has * focus. */ public static final int KEYCODE_NAVIGATE_OUT = 263; - - private static final int LAST_KEYCODE = KEYCODE_NAVIGATE_OUT; + /** Key code constant: Skip forward media key. */ + public static final int KEYCODE_MEDIA_SKIP_FORWARD = 272; + /** Key code constant: Skip backward media key. */ + public static final int KEYCODE_MEDIA_SKIP_BACKWARD = 273; + /** Key code constant: Step forward media key. + * Steps media forward, one frame at a time. */ + public static final int KEYCODE_MEDIA_STEP_FORWARD = 274; + /** Key code constant: Step backward media key. + * Steps media backward, one frame at a time. */ + public static final int KEYCODE_MEDIA_STEP_BACKWARD = 275; + + private static final int LAST_KEYCODE = KEYCODE_MEDIA_STEP_BACKWARD; // NOTE: If you add a new keycode here you must also add it to: // isSystem() diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index fab81a424f76..52d6cbec4abb 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -43,6 +43,7 @@ import android.util.AttributeSet; import android.util.Log; import android.util.Pools.SynchronizedPool; import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.Animation; @@ -2902,13 +2903,58 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int childrenCount = getChildCount(); if (childrenCount > 0) { structure.setChildCount(childrenCount); - final ArrayList<View> preorderedList = buildOrderedChildList(); - final boolean customOrder = preorderedList == null + ArrayList<View> preorderedList = buildOrderedChildList(); + boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); final View[] children = mChildren; for (int i=0; i<childrenCount; i++) { - final int childIndex = customOrder - ? getChildDrawingOrder(childrenCount, i) : i; + int childIndex; + try { + childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i; + } catch (IndexOutOfBoundsException e) { + childIndex = i; + if (mContext.getApplicationInfo().targetSdkVersion + < Build.VERSION_CODES.M) { + Log.w(TAG, "Bad getChildDrawingOrder while collecting assist @ " + + i + " of " + childrenCount, e); + // At least one app is failing when we call getChildDrawingOrder + // at this point, so deal semi-gracefully with it by falling back + // on the basic order. + customOrder = false; + if (i > 0) { + // If we failed at the first index, there really isn't + // anything to do -- we will just proceed with the simple + // sequence order. + // Otherwise, we failed in the middle, so need to come up + // with an order for the remaining indices and use that. + // Failed at the first one, easy peasy. + int[] permutation = new int[childrenCount]; + SparseBooleanArray usedIndices = new SparseBooleanArray(); + // Go back and collected the indices we have done so far. + for (int j=0; j<i; j++) { + permutation[j] = getChildDrawingOrder(childrenCount, j); + usedIndices.put(permutation[j], true); + } + // Fill in the remaining indices with indices that have not + // yet been used. + int nextIndex = 0; + for (int j=i; j<childrenCount; j++) { + while (usedIndices.get(nextIndex, false)) { + nextIndex++; + } + permutation[j] = nextIndex; + nextIndex++; + } + // Build the final view list. + preorderedList = new ArrayList<>(childrenCount); + for (int j=0; j<childrenCount; j++) { + preorderedList.add(children[permutation[j]]); + } + } + } else { + throw e; + } + } final View child = (preorderedList == null) ? children[childIndex] : preorderedList.get(childIndex); ViewStructure cstructure = structure.newChild(i); diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index e13b96fb5ba1..ddbaa9db6444 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -384,6 +384,10 @@ public class ImageView extends View { assigned. */ public Drawable getDrawable() { + if (mDrawable == mRecycleableBitmapDrawable) { + // Consider our cached version dirty since app code now has a reference to it + mRecycleableBitmapDrawable = null; + } return mDrawable; } diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index b4cbf35ac60e..f9fa0272f147 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -105,7 +105,10 @@ public class PopupWindow { /** View that handles event dispatch and content transitions. */ private PopupDecorView mDecorView; - /** The contents of the popup. */ + /** View that holds the background and may animate during a transition. */ + private View mBackgroundView; + + /** The contents of the popup. May be identical to the background view. */ private View mContentView; private boolean mFocusable; @@ -1111,18 +1114,18 @@ public class PopupWindow { if (aboveAnchor != mAboveAnchor) { mAboveAnchor = aboveAnchor; - if (mBackground != null) { - // If the background drawable provided was a StateListDrawable with above-anchor - // and below-anchor states, use those. Otherwise rely on refreshDrawableState to - // do the job. + if (mBackground != null && mBackgroundView != null) { + // If the background drawable provided was a StateListDrawable + // with above-anchor and below-anchor states, use those. + // Otherwise, rely on refreshDrawableState to do the job. if (mAboveAnchorBackgroundDrawable != null) { if (mAboveAnchor) { - mDecorView.setBackground(mAboveAnchorBackgroundDrawable); + mBackgroundView.setBackground(mAboveAnchorBackgroundDrawable); } else { - mDecorView.setBackground(mBelowAnchorBackgroundDrawable); + mBackgroundView.setBackground(mBelowAnchorBackgroundDrawable); } } else { - mDecorView.refreshDrawableState(); + mBackgroundView.refreshDrawableState(); } } } @@ -1164,22 +1167,21 @@ public class PopupWindow { // When a background is available, we embed the content view within // another view that owns the background drawable. - final View backgroundView; if (mBackground != null) { - backgroundView = createBackgroundView(mContentView); - backgroundView.setBackground(mBackground); + mBackgroundView = createBackgroundView(mContentView); + mBackgroundView.setBackground(mBackground); } else { - backgroundView = mContentView; + mBackgroundView = mContentView; } - mDecorView = createDecorView(backgroundView); + mDecorView = createDecorView(mBackgroundView); // The background owner should be elevated so that it casts a shadow. - backgroundView.setElevation(mElevation); + mBackgroundView.setElevation(mElevation); // We may wrap that in another view, so we'll need to manually specify // the surface insets. - final int surfaceInset = (int) Math.ceil(backgroundView.getZ() * 2); + final int surfaceInset = (int) Math.ceil(mBackgroundView.getZ() * 2); p.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset); p.hasManualSurfaceInsets = true; @@ -1650,6 +1652,7 @@ public class PopupWindow { // This needs to stay until after all transitions have ended since we // need the reference to cancel transitions in preparePopup(). mDecorView = null; + mBackgroundView = null; mIsTransitioningToDismiss = false; } diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index d954b7161513..55493c3a9576 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -28,6 +28,7 @@ import android.view.View; public class MetricsLogger implements MetricsConstants { // Temporary constants go here, to await migration to MetricsConstants. // next value is 239; + public static final int ACTION_ASSIST_LONG_PRESS = 239; public static void visible(Context context, int category) throws IllegalArgumentException { if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) { diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index db88962efccc..7a725ae75e90 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -298,11 +298,11 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode, String8 storageSource; if (mount_mode == MOUNT_EXTERNAL_DEFAULT) { - storageSource = "/mnt/runtime_default"; + storageSource = "/mnt/runtime/default"; } else if (mount_mode == MOUNT_EXTERNAL_READ) { - storageSource = "/mnt/runtime_read"; + storageSource = "/mnt/runtime/read"; } else if (mount_mode == MOUNT_EXTERNAL_WRITE) { - storageSource = "/mnt/runtime_write"; + storageSource = "/mnt/runtime/write"; } else { // Sane default of no storage visible return true; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 1f47ce37e2ba..699e11397dc7 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2575,7 +2575,7 @@ <permission android:name="android.permission.QUERY_DO_NOT_ASK_CREDENTIALS_ON_BOOT" android:protectionLevel="signature" /> - <!-- @SystemApi Allows applications to kill UIDs. + <!-- Allows applications to kill UIDs. <p>Not for use by third-party applications. @hide --> <permission android:name="android.permission.KILL_UID" diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index b1925ba2bc63..67abe8d2e1dc 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1806,6 +1806,10 @@ i <enum name="KEYCODE_NAVIGATE_NEXT" value="261" /> <enum name="KEYCODE_NAVIGATE_IN" value="262" /> <enum name="KEYCODE_NAVIGATE_OUT" value="263" /> + <enum name="KEYCODE_MEDIA_SKIP_FORWARD" value="272" /> + <enum name="KEYCODE_MEDIA_SKIP_BACKWARD" value="273" /> + <enum name="KEYCODE_MEDIA_STEP_FORWARD" value="274" /> + <enum name="KEYCODE_MEDIA_STEP_BACKWARD" value="275" /> </attr> <!-- ***************************************************************** --> diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index 61042646eeab..fef65eea5f4f 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -19,6 +19,8 @@ package android.media; import android.annotation.NonNull; import android.util.SparseIntArray; +import java.util.TreeSet; + /** * Class to provide information about the audio devices. */ @@ -109,6 +111,14 @@ public final class AudioDeviceInfo { * A device type connected over IP. */ public static final int TYPE_IP = 20; + /** + * @hide + * A remote-submix device. + * We need this for CTS, but it is not part of the external API. + * FIXME It has been suggested that CTS should only be testing public APIs. + * Consider this for a public API. + */ + public static final int TYPE_REMOTE_SUBMIX = 0x7FFF; private final AudioDevicePort mPort; @@ -193,13 +203,24 @@ public final class AudioDeviceInfo { * Note: an empty array indicates that the device supports arbitrary channel counts. */ public @NonNull int[] getChannelCounts() { - int[] masks = getChannelMasks(); - int[] counts = new int[masks.length]; - // TODO: consider channel index masks - for (int mask_index = 0; mask_index < masks.length; mask_index++) { - counts[mask_index] = isSink() - ? AudioFormat.channelCountFromOutChannelMask(masks[mask_index]) - : AudioFormat.channelCountFromInChannelMask(masks[mask_index]); + TreeSet<Integer> countSet = new TreeSet<Integer>(); + + // Channel Masks + for (int mask : getChannelMasks()) { + countSet.add(isSink() ? + AudioFormat.channelCountFromOutChannelMask(mask) + : AudioFormat.channelCountFromInChannelMask(mask)); + } + + // Index Masks + for (int index_mask : getChannelIndexMasks()) { + countSet.add(Integer.bitCount(index_mask)); + } + + int[] counts = new int[countSet.size()]; + int index = 0; + for (int count : countSet) { + counts[index++] = count; } return counts; } @@ -265,6 +286,7 @@ public final class AudioDeviceInfo { INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_FM, TYPE_FM); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_AUX_LINE, TYPE_AUX_LINE); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_IP, TYPE_IP); + INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO); @@ -282,10 +304,7 @@ public final class AudioDeviceInfo { INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_SPDIF, TYPE_LINE_DIGITAL); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, TYPE_BLUETOOTH_A2DP); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_IP, TYPE_IP); - - // not covered here, legacy - //AudioSystem.DEVICE_OUT_REMOTE_SUBMIX - //AudioSystem.DEVICE_IN_REMOTE_SUBMIX + INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX); // privileges mapping to output device EXT_TO_INT_DEVICE_MAPPING = new SparseIntArray(); diff --git a/media/java/android/media/MediaSync.java b/media/java/android/media/MediaSync.java index b37e02c1e219..5522d362bc09 100644 --- a/media/java/android/media/MediaSync.java +++ b/media/java/android/media/MediaSync.java @@ -55,7 +55,7 @@ import java.util.List; * } * }, null); * // This needs to be done since sync is paused on creation. - * sync.setPlaybackRate(1.0f, MediaSync.PLAYBACK_RATE_AUDIO_MODE_RESAMPLE); + * sync.setPlaybackParams(new PlaybackParams().setSpeed(1.f)); * * for (;;) { * ... @@ -69,7 +69,7 @@ import java.util.List; * ... * ... * } - * sync.setPlaybackRate(0.0f, MediaSync.PLAYBACK_RATE_AUDIO_MODE_RESAMPLE); + * sync.setPlaybackParams(new PlaybackParams().setSpeed(0.f)); * sync.release(); * sync = null; * diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index d99f741366bd..e74334b220cd 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -447,8 +447,10 @@ public class SettingsBackupAgent extends BackupAgentHelper { Settings.Global.putInt(cr, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0); } - // !!! Give the wifi stack a moment to quiesce - try { Thread.sleep(1500); } catch (InterruptedException e) {} + // !!! Give the wifi stack a moment to quiesce. We've observed the + // response to disabling WIFI_SCAN_ALWAYS_AVAILABLE taking more + // than 1500ms, so we wait a generous 2500 here before proceeding. + try { Thread.sleep(2500); } catch (InterruptedException e) {} if (restoredSupplicantData != null) { restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, restoredSupplicantData, restoredSupplicantData.length); diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png Binary files differindex d2760bb912e2..aa9f6d43b5d0 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png Binary files differindex 5cbf41848172..151caea27a28 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png Binary files differindex df43e21b47d1..613afce784f1 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png Binary files differindex 6fab1d645dff..eb8042609d90 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png Binary files differindex 1d8c3af17716..34a11df8a587 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png Binary files differindex 47c6ebd5e764..1c1e78cb0a7c 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png Binary files differindex 66de0ec75ec9..7c25fc510d5b 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png Binary files differindex 30c65f51a128..1ee9cf5f352d 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png Binary files differindex a3562850ef9c..987aac50d810 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png Binary files differindex 42893ff340b1..433e5a74d3f6 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png Binary files differindex ba2d0b2642ce..0e2a14d3b54b 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png Binary files differindex 94a74b189abf..f810704c9aa7 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png Binary files differindex 29da099f6d82..be03cbe16ddb 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png Binary files differindex ada2879c7b3b..b6b1615c5fa4 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png Binary files differindex 59b32f2dd178..f16aa4882dd4 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png Binary files differindex ba66d27f1199..109aeedab42a 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back.png Binary files differnew file mode 100644 index 000000000000..a059704f9848 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime.png Binary files differnew file mode 100644 index 000000000000..8f00a64b3603 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home.png Binary files differnew file mode 100644 index 000000000000..194d39f9f137 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent.png Binary files differnew file mode 100644 index 000000000000..046d850f3e0c --- /dev/null +++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 9f86a52c20c1..c1df788d4108 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -841,11 +841,6 @@ public class KeyguardViewMediator extends SystemUI { synchronized (this) { if (DEBUG) Log.d(TAG, "setKeyguardEnabled(" + enabled + ")"); - if (isSecure()) { - Log.d(TAG, "current mode is SecurityMode, ignore hide keyguard"); - return; - } - mExternallyEnabled = enabled; if (!enabled && mShowing) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 789457da6e83..b47fb3044897 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -419,8 +419,10 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView updateRecentsTasks(); // If this is a new instance from a configuration change, then we have to manually trigger - // the enter animation state - if (mConfig.launchedHasConfigurationChanged) { + // the enter animation state, or if recents was relaunched by AM, without going through + // the normal mechanisms + boolean wasLaunchedByAm = !mConfig.launchedFromHome && !mConfig.launchedFromAppWithThumbnail; + if (mConfig.launchedHasConfigurationChanged || wasLaunchedByAm) { onEnterAnimationTriggered(); } @@ -454,6 +456,16 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Unregister any broadcast receivers for the task loader loader.unregisterReceivers(); + + // Workaround for b/22542869, if the RecentsActivity is started again, but without going + // through SystemUI, we need to reset the config launch flags to ensure that we do not + // wait on the system to send a signal that was never queued. + mConfig.launchedFromHome = false; + mConfig.launchedFromSearchHome = false; + mConfig.launchedFromAppWithThumbnail = false; + mConfig.launchedToTaskId = -1; + mConfig.launchedWithAltTab = false; + mConfig.launchedHasConfigurationChanged = false; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 86755d178e8c..efd72a73371b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -603,7 +603,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // Lastly, call to the icon policy to install/update all the icons. mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController, - mUserInfoController); + mUserInfoController, mBluetoothController); mIconPolicy.setCurrentUserSetup(mUserSetup); mSettingsObserver.onChange(false); // set up @@ -1056,6 +1056,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (shouldDisableNavbarGestures()) { return false; } + MetricsLogger.action(mContext, MetricsLogger.ACTION_ASSIST_LONG_PRESS); mAssistManager.startAssist(new Bundle() /* args */); awakenDreams(); if (mNavigationBarView != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 53dae5cfca45..540b9d003a17 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -21,7 +21,6 @@ import android.app.AlarmManager; import android.app.AlarmManager.AlarmClockInfo; import android.app.IUserSwitchObserver; import android.app.StatusBarManager; -import android.bluetooth.BluetoothAdapter; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -41,6 +40,8 @@ import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.systemui.R; import com.android.systemui.qs.tiles.DndTile; +import com.android.systemui.statusbar.policy.BluetoothController; +import com.android.systemui.statusbar.policy.BluetoothController.Callback; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.CastController.CastDevice; import com.android.systemui.statusbar.policy.HotspotController; @@ -51,7 +52,7 @@ import com.android.systemui.statusbar.policy.UserInfoController; * bar at boot time. It goes through the normal API for icons, even though it probably * strictly doesn't need to. */ -public class PhoneStatusBarPolicy { +public class PhoneStatusBarPolicy implements Callback { private static final String TAG = "PhoneStatusBarPolicy"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -82,12 +83,11 @@ public class PhoneStatusBarPolicy { private int mZen; - private boolean mBluetoothEnabled = false; - private boolean mManagedProfileFocused = false; private boolean mManagedProfileIconVisible = true; private boolean mKeyguardVisible = true; + private BluetoothController mBluetooth; private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override @@ -96,10 +96,6 @@ public class PhoneStatusBarPolicy { if (action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) { updateAlarm(); } - else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED) || - action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) { - updateBluetooth(); - } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) || action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) { updateVolumeZen(); @@ -114,10 +110,12 @@ public class PhoneStatusBarPolicy { }; public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot, - UserInfoController userInfoController) { + UserInfoController userInfoController, BluetoothController bluetooth) { mContext = context; mCast = cast; mHotspot = hotspot; + mBluetooth = bluetooth; + mBluetooth.addStateChangedCallback(this); mService = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE); mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); mUserInfoController = userInfoController; @@ -127,8 +125,6 @@ public class PhoneStatusBarPolicy { filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION); - filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); - filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED); mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); @@ -275,23 +271,31 @@ public class PhoneStatusBarPolicy { updateAlarm(); } + @Override + public void onBluetoothDevicesChanged() { + updateBluetooth(); + } + + @Override + public void onBluetoothStateChange(boolean enabled) { + updateBluetooth(); + } + private final void updateBluetooth() { - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); int iconId = R.drawable.stat_sys_data_bluetooth; String contentDescription = mContext.getString(R.string.accessibility_quick_settings_bluetooth_on); - if (adapter != null) { - mBluetoothEnabled = (adapter.getState() == BluetoothAdapter.STATE_ON); - if (adapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED) { + boolean bluetoothEnabled = false; + if (mBluetooth != null) { + bluetoothEnabled = mBluetooth.isBluetoothEnabled(); + if (mBluetooth.isBluetoothConnected()) { iconId = R.drawable.stat_sys_data_bluetooth_connected; contentDescription = mContext.getString(R.string.accessibility_bluetooth_connected); } - } else { - mBluetoothEnabled = false; } mService.setIcon(SLOT_BLUETOOTH, iconId, 0, contentDescription); - mService.setIconVisibility(SLOT_BLUETOOTH, mBluetoothEnabled); + mService.setIconVisibility(SLOT_BLUETOOTH, bluetoothEnabled); } private final void updateTTY(Intent intent) { diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index 53e8d147ad3c..d10a457747a3 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -766,6 +766,15 @@ class MountService extends IMountService.Stub } } + private void addInternalVolume() { + // Create a stub volume that represents internal storage + final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL, + VolumeInfo.TYPE_PRIVATE, null, null); + internal.state = VolumeInfo.STATE_MOUNTED; + internal.path = Environment.getDataDirectory().getAbsolutePath(); + mVolumes.put(internal.id, internal); + } + private void resetIfReadyAndConnectedLocked() { Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady + ", mDaemonConnected=" + mDaemonConnected); @@ -775,12 +784,7 @@ class MountService extends IMountService.Stub mDisks.clear(); mVolumes.clear(); - // Create a stub volume that represents internal storage - final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL, - VolumeInfo.TYPE_PRIVATE, null, null); - internal.state = VolumeInfo.STATE_MOUNTED; - internal.path = Environment.getDataDirectory().getAbsolutePath(); - mVolumes.put(internal.id, internal); + addInternalVolume(); try { mConnector.execute("volume", "reset"); @@ -1412,6 +1416,8 @@ class MountService extends IMountService.Stub userFilter.addAction(Intent.ACTION_USER_REMOVED); mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler); + addInternalVolume(); + // Add ourself to the Watchdog monitors if enabled. if (WATCHDOG_ENABLE) { Watchdog.getInstance().addMonitor(this); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b8d32c3afb93..3d523d9be2d3 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4118,7 +4118,7 @@ public final class ActivityManagerService extends ActivityManagerNative final Intent intent; final int userId; synchronized (this) { - task = mRecentTasks.taskForIdLocked(taskId); + task = mStackSupervisor.anyTaskForIdLocked(taskId); if (task == null) { throw new IllegalArgumentException("Task " + taskId + " not found."); } @@ -5521,7 +5521,7 @@ public final class ActivityManagerService extends ActivityManagerNative // If no package is specified, we call all processes under the // give user id. if (packageName == null) { - if (app.userId != userId) { + if (userId != UserHandle.USER_ALL && app.userId != userId) { continue; } if (appId >= 0 && UserHandle.getAppId(app.uid) != appId) { @@ -8805,7 +8805,7 @@ public final class ActivityManagerService extends ActivityManagerNative final long origId = Binder.clearCallingIdentity(); try { int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot); - final TaskRecord task = mRecentTasks.taskForIdLocked(taskId); + final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId); if (task != null) { if (mStackSupervisor.isLockedTask(task)) { mStackSupervisor.showLockTaskToast(); @@ -11226,13 +11226,12 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void killUid(int uid, String reason) { + public void killUid(int appId, int userId, String reason) { enforceCallingPermission(Manifest.permission.KILL_UID, "killUid"); synchronized (this) { final long identity = Binder.clearCallingIdentity(); try { - killPackageProcessesLocked(null, UserHandle.getAppId(uid), - UserHandle.getUserId(uid), + killPackageProcessesLocked(null, appId, userId, ProcessList.PERSISTENT_PROC_ADJ, false, true, true, true, reason != null ? reason : "kill uid"); } finally { @@ -20573,7 +20572,7 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (ActivityManagerService.this) { long origId = Binder.clearCallingIdentity(); try { - TaskRecord tr = mRecentTasks.taskForIdLocked(mTaskId); + TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(mTaskId); if (tr == null) { throw new IllegalArgumentException("Unable to find task ID " + mTaskId); } @@ -20600,7 +20599,7 @@ public final class ActivityManagerService extends ActivityManagerNative TaskRecord tr; IApplicationThread appThread; synchronized (ActivityManagerService.this) { - tr = mRecentTasks.taskForIdLocked(mTaskId); + tr = mStackSupervisor.anyTaskForIdLocked(mTaskId); if (tr == null) { throw new IllegalArgumentException("Unable to find task ID " + mTaskId); } @@ -20621,7 +20620,7 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (ActivityManagerService.this) { long origId = Binder.clearCallingIdentity(); try { - TaskRecord tr = mRecentTasks.taskForIdLocked(mTaskId); + TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(mTaskId); if (tr == null) { throw new IllegalArgumentException("Unable to find task ID " + mTaskId); } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 71fd49b71c98..7c796612feeb 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1509,9 +1509,13 @@ public final class ActivityStackSupervisor implements DisplayListener { intent.addCategory(Intent.CATEGORY_VOICE); if (!AppGlobals.getPackageManager().activitySupportsIntent( intent.getComponent(), intent, resolvedType)) { + Slog.w(TAG, + "Activity being started in current voice task does not support voice: " + + intent); err = ActivityManager.START_NOT_VOICE_COMPATIBLE; } } catch (RemoteException e) { + Slog.w(TAG, "Failure checking voice capabilities", e); err = ActivityManager.START_NOT_VOICE_COMPATIBLE; } } @@ -1523,9 +1527,13 @@ public final class ActivityStackSupervisor implements DisplayListener { try { if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(), intent, resolvedType)) { + Slog.w(TAG, + "Activity being started in new voice task does not support: " + + intent); err = ActivityManager.START_NOT_VOICE_COMPATIBLE; } } catch (RemoteException e) { + Slog.w(TAG, "Failure checking voice capabilities", e); err = ActivityManager.START_NOT_VOICE_COMPATIBLE; } } diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 7e2ad2969843..9da30bff8c94 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -786,7 +786,8 @@ final class TaskRecord { } boolean isLockTaskWhitelistedLocked() { - if (mCallingPackage == null) { + String pkg = (realActivity != null) ? realActivity.getPackageName() : null; + if (pkg == null) { return false; } String[] packages = mService.mLockTaskPackages.get(userId); @@ -794,7 +795,7 @@ final class TaskRecord { return false; } for (int i = packages.length - 1; i >= 0; --i) { - if (mCallingPackage.equals(packages[i])) { + if (pkg.equals(packages[i])) { return true; } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index a0ededfb7941..7565e9d84395 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -5150,7 +5150,9 @@ public class AudioService extends IAudioService.Stub { continue; } try { - ActivityManagerNative.getDefault().killUid(pkg.applicationInfo.uid, + final int uid = pkg.applicationInfo.uid; + ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid), + UserHandle.getUserId(uid), "killBackgroundUserProcessesWithAudioRecordPermission"); } catch (RemoteException e) { Log.w(TAG, "Error calling killUid", e); diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 31fa5c44751d..57d7758fb6aa 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -88,7 +88,6 @@ public class ZenModeHelper { private int mUser = UserHandle.USER_OWNER; private ZenModeConfig mConfig; private AudioManagerInternal mAudioManager; - private int mPreviousRingerMode = -1; private boolean mEffectsSuppressed; public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) { @@ -236,7 +235,6 @@ public class ZenModeHelper { } pw.print(prefix); pw.print("mUser="); pw.println(mUser); dump(pw, prefix, "mConfig", mConfig); - pw.print(prefix); pw.print("mPreviousRingerMode="); pw.println(mPreviousRingerMode); pw.print(prefix); pw.print("mEffectsSuppressed="); pw.println(mEffectsSuppressed); mFiltering.dump(pw, prefix); mConditions.dump(pw, prefix); @@ -357,6 +355,17 @@ public class ZenModeHelper { Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen); } + private int getPreviousRingerModeSetting() { + return Global.getInt(mContext.getContentResolver(), + Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL); + } + + private void setPreviousRingerModeSetting(Integer previousRingerLevel) { + Global.putString( + mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL, + previousRingerLevel == null ? null : Integer.toString(previousRingerLevel)); + } + private boolean evaluateZenMode(String reason, boolean setRingerMode) { if (DEBUG) Log.d(TAG, "evaluateZenMode"); final ArraySet<ZenRule> automaticRules = new ArraySet<ZenRule>(); @@ -430,16 +439,15 @@ public class ZenModeHelper { case Global.ZEN_MODE_NO_INTERRUPTIONS: case Global.ZEN_MODE_ALARMS: if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) { - mPreviousRingerMode = ringerModeInternal; + setPreviousRingerModeSetting(ringerModeInternal); newRingerModeInternal = AudioManager.RINGER_MODE_SILENT; } break; case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: case Global.ZEN_MODE_OFF: if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) { - newRingerModeInternal = mPreviousRingerMode != -1 ? mPreviousRingerMode - : AudioManager.RINGER_MODE_NORMAL; - mPreviousRingerMode = -1; + newRingerModeInternal = getPreviousRingerModeSetting(); + setPreviousRingerModeSetting(null); } break; } @@ -593,7 +601,7 @@ public class ZenModeHelper { && mZenMode != Global.ZEN_MODE_ALARMS) { newZen = Global.ZEN_MODE_ALARMS; } - mPreviousRingerMode = ringerModeOld; + setPreviousRingerModeSetting(ringerModeOld); } break; case AudioManager.RINGER_MODE_VIBRATE: diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java index 3227ef857f5e..71a2d59fb34b 100644 --- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java @@ -34,6 +34,7 @@ import android.provider.CalendarContract; import android.provider.ContactsContract; import android.provider.MediaStore; import android.provider.Telephony.Sms.Intents; +import android.security.Credentials; import android.util.ArraySet; import android.util.Log; @@ -298,6 +299,15 @@ final class DefaultPermissionGrantPolicy { grantRuntimePermissionsLPw(storagePackage, STORAGE_PERMISSIONS, userId); } + // CertInstaller + Intent certInstallerIntent = new Intent(Credentials.INSTALL_ACTION); + PackageParser.Package certInstallerPackage = getDefaultSystemHandlerActivityPackageLPr( + certInstallerIntent, userId); + if (certInstallerPackage != null + && doesPackageSupportRuntimePermissions(certInstallerPackage)) { + grantRuntimePermissionsLPw(certInstallerPackage, STORAGE_PERMISSIONS, true, userId); + } + // Dialer if (dialerAppPackageNames == null) { Intent dialerIntent = new Intent(Intent.ACTION_DIAL); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4f945bebdca6..6a4ae3d0c9b2 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3469,10 +3469,11 @@ public class PackageManagerService extends IPackageManager.Stub { } case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: { + final int appId = UserHandle.getAppId(pkg.applicationInfo.uid); mHandler.post(new Runnable() { @Override public void run() { - killSettingPackagesForUser(sb, userId, KILL_APP_REASON_GIDS_CHANGED); + killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED); } }); } break; @@ -3516,7 +3517,7 @@ public class PackageManagerService extends IPackageManager.Stub { enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "revokeRuntimePermission"); - final SettingBase sb; + final int appId; synchronized (mPackages) { final PackageParser.Package pkg = mPackages.get(packageName); @@ -3531,7 +3532,7 @@ public class PackageManagerService extends IPackageManager.Stub { enforceDeclaredAsUsedAndRuntimePermission(pkg, bp); - sb = (SettingBase) pkg.mExtras; + SettingBase sb = (SettingBase) pkg.mExtras; if (sb == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } @@ -3553,9 +3554,11 @@ public class PackageManagerService extends IPackageManager.Stub { // Critical, after this call app should never have the permission. mSettings.writeRuntimePermissionsForUserLPr(userId, true); + + appId = UserHandle.getAppId(pkg.applicationInfo.uid); } - killSettingPackagesForUser(sb, userId, KILL_APP_REASON_PERMISSIONS_REVOKED); + killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED); } @Override @@ -3859,28 +3862,15 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private void killSettingPackagesForUser(SettingBase sb, int userId, String reason) { + private void killUid(int appId, int userId, String reason) { final long identity = Binder.clearCallingIdentity(); try { - if (sb instanceof SharedUserSetting) { - SharedUserSetting sus = (SharedUserSetting) sb; - final int packageCount = sus.packages.size(); - for (int i = 0; i < packageCount; i++) { - PackageSetting susPs = sus.packages.valueAt(i); - if (userId == UserHandle.USER_ALL) { - killApplication(susPs.pkg.packageName, susPs.appId, reason); - } else { - final int uid = UserHandle.getUid(userId, susPs.appId); - killUid(uid, reason); - } - } - } else if (sb instanceof PackageSetting) { - PackageSetting ps = (PackageSetting) sb; - if (userId == UserHandle.USER_ALL) { - killApplication(ps.pkg.packageName, ps.appId, reason); - } else { - final int uid = UserHandle.getUid(userId, ps.appId); - killUid(uid, reason); + IActivityManager am = ActivityManagerNative.getDefault(); + if (am != null) { + try { + am.killUid(appId, userId, reason); + } catch (RemoteException e) { + /* ignore - same process */ } } } finally { @@ -3888,17 +3878,6 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private static void killUid(int uid, String reason) { - IActivityManager am = ActivityManagerNative.getDefault(); - if (am != null) { - try { - am.killUid(uid, reason); - } catch (RemoteException e) { - /* ignore - same process */ - } - } - } - /** * Compares two sets of signatures. Returns: * <br /> @@ -12821,7 +12800,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public void run() { // This has to happen with no lock held. - killSettingPackagesForUser(deletedPs, userIdToKill, + killApplication(deletedPs.name, deletedPs.appId, KILL_APP_REASON_GIDS_CHANGED); } }); @@ -12942,6 +12921,10 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { PackageSetting ps = mSettings.mPackages.get(newPkg.packageName); + // Propagate the permissions state as we do not want to drop on the floor + // runtime permissions. The update permissions method below will take + // care of removing obsolete permissions and grant install permissions. + ps.getPermissionsState().copyFrom(newPs.getPermissionsState()); updatePermissionsLPw(newPkg.packageName, newPkg, UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG); @@ -13404,13 +13387,11 @@ public class PackageManagerService extends IPackageManager.Stub { case PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: { writeRuntimePermissions = true; - // If gids changed for this user, kill all affected packages. + final int appId = ps.appId; mHandler.post(new Runnable() { @Override public void run() { - // This has to happen with no lock held. - killSettingPackagesForUser(ps, userId, - KILL_APP_REASON_GIDS_CHANGED); + killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED); } }); } break; diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 670756216dae..264170cf1f21 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -135,6 +135,11 @@ public class UserManagerService extends IUserManager.Stub { // without first making sure that the rest of the framework is prepared for it. private static final int MAX_MANAGED_PROFILES = 1; + /** + * Flag indicating whether device credentials are shared among same-user profiles. + */ + private static final boolean CONFIG_PROFILES_SHARE_CREDENTIAL = true; + // Set of user restrictions, which can only be enforced by the system private static final Set<String> SYSTEM_CONTROLLED_RESTRICTIONS = Sets.newArraySet( UserManager.DISALLOW_RECORD_AUDIO); @@ -241,7 +246,7 @@ public class UserManagerService extends IUserManager.Stub { } for (int i = 0; i < partials.size(); i++) { UserInfo ui = partials.get(i); - Slog.w(LOG_TAG, "Removing partially created user #" + i + Slog.w(LOG_TAG, "Removing partially created user " + ui.id + " (name=" + ui.name + ")"); removeUserStateLocked(ui.id); } @@ -317,6 +322,21 @@ public class UserManagerService extends IUserManager.Stub { } @Override + public int getCredentialOwnerProfile(int userHandle) { + checkManageUsersPermission("get the credential owner"); + if (CONFIG_PROFILES_SHARE_CREDENTIAL) { + synchronized (mPackagesLock) { + UserInfo profileParent = getProfileParentLocked(userHandle); + if (profileParent != null) { + return profileParent.id; + } + } + } + + return userHandle; + } + + @Override public UserInfo getProfileParent(int userHandle) { checkManageUsersPermission("get the profile parent"); synchronized (mPackagesLock) { @@ -943,7 +963,7 @@ public class UserManagerService extends IUserManager.Stub { } } - private void writeRestrictionsLocked(XmlSerializer serializer, Bundle restrictions) + private void writeRestrictionsLocked(XmlSerializer serializer, Bundle restrictions) throws IOException { serializer.startTag(null, TAG_RESTRICTIONS); writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_WIFI); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index da8fb702a56e..c4ff277945a2 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -5229,9 +5229,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private boolean shouldDispatchInputWhenNonInteractive() { - // Send events to keyguard while the screen is on. - if (isKeyguardShowingAndNotOccluded() && mDisplay != null - && mDisplay.getState() != Display.STATE_OFF) { + if (mDisplay == null || mDisplay.getState() == Display.STATE_OFF) { + return false; + } + // Send events to keyguard while the screen is on and it's showing. + if (isKeyguardShowingAndNotOccluded()) { return true; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 26e75bd30df1..bc5ef36fc347 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -155,7 +155,6 @@ import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; -import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_SECURE; @@ -5367,6 +5366,12 @@ public class WindowManagerService extends IWindowManager.Stub != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires DISABLE_KEYGUARD permission"); } + // If this isn't coming from the system then don't allow disabling the lockscreen + // to bypass security. + if (Binder.getCallingUid() != Process.SYSTEM_UID && isKeyguardSecure()) { + Log.d(TAG, "current mode is SecurityMode, ignore hide keyguard"); + return; + } if (token == null) { throw new IllegalArgumentException("token == null"); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java index 04d6d98fe2b2..1788e88c82fd 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java @@ -48,6 +48,7 @@ import android.view.WindowManager; import com.android.internal.app.IAssistScreenshotReceiver; import com.android.internal.app.IVoiceInteractionSessionShowCallback; import com.android.internal.app.IVoiceInteractor; +import com.android.internal.logging.MetricsLogger; import com.android.internal.os.IResultReceiver; import com.android.server.LocalServices; import com.android.server.statusbar.StatusBarManagerInternal; @@ -225,6 +226,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED && structureEnabled) { try { + MetricsLogger.count(mContext, "assist_with_context", 1); if (mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL, mAssistReceiver, activityToken)) { needDisclosure = true; @@ -249,6 +251,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED && screenshotEnabled) { try { + MetricsLogger.count(mContext, "assist_with_screen", 1); needDisclosure = true; mIWindowManager.requestAssistScreenshot(mScreenshotReceiver); } catch (RemoteException e) { diff --git a/tools/layoutlib/.idea/inspectionProfiles/Project_Default.xml b/tools/layoutlib/.idea/inspectionProfiles/Project_Default.xml index 0ac7a44ea38a..5bb3e3e47922 100644 --- a/tools/layoutlib/.idea/inspectionProfiles/Project_Default.xml +++ b/tools/layoutlib/.idea/inspectionProfiles/Project_Default.xml @@ -1,3 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> <component name="InspectionProjectProfileManager"> <profile version="1.0" is_locked="false"> <option name="myName" value="Project Default" /> @@ -7,5 +8,6 @@ <option name="CHECK_TRY_CATCH_SECTION" value="true" /> <option name="CHECK_METHOD_BODY" value="true" /> </inspection_tool> + <inspection_tool class="ToArrayCallWithZeroLengthArrayArgument" enabled="false" level="WARNING" enabled_by_default="false" /> </profile> </component>
\ No newline at end of file diff --git a/tools/layoutlib/bridge/src/android/widget/SimpleMonthView_Delegate.java b/tools/layoutlib/bridge/src/android/widget/SimpleMonthView_Delegate.java new file mode 100644 index 000000000000..8e41e5162513 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/widget/SimpleMonthView_Delegate.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2015 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.widget; + +import com.android.tools.layoutlib.annotations.LayoutlibDelegate; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.icu.text.SimpleDateFormat; +import android.text.format.DateFormat; + +import java.util.Calendar; +import java.util.Locale; + +/** + * Delegate that provides implementation for some methods in {@link SimpleMonthView}. + * <p/> + * Through the layoutlib_create tool, selected methods of SimpleMonthView have been replaced by + * calls to methods of the same name in this delegate class. + * <p/> + * The main purpose of this class is to use {@link android.icu.text.SimpleDateFormat} instead of + * {@link java.text.SimpleDateFormat}. + */ +public class SimpleMonthView_Delegate { + + private static final String DEFAULT_TITLE_FORMAT = "MMMMy"; + private static final String DAY_OF_WEEK_FORMAT = "EEEEE"; + + // Maintain a cache of the last view used, so that the formatters can be reused. + @Nullable private static SimpleMonthView sLastView; + @Nullable private static SimpleMonthView_Delegate sLastDelegate; + + private SimpleDateFormat mTitleFormatter; + private SimpleDateFormat mDayOfWeekFormatter; + + private Locale locale; + + @LayoutlibDelegate + /*package*/ static CharSequence getTitle(SimpleMonthView view) { + if (view.mTitle == null) { + SimpleMonthView_Delegate delegate = getDelegate(view); + if (delegate.mTitleFormatter == null) { + delegate.mTitleFormatter = new SimpleDateFormat(DateFormat.getBestDateTimePattern( + getLocale(delegate, view), DEFAULT_TITLE_FORMAT)); + } + view.mTitle = delegate.mTitleFormatter.format(view.mCalendar.getTime()); + } + return view.mTitle; + } + + @LayoutlibDelegate + /*package*/ static String getDayOfWeekLabel(SimpleMonthView view, int dayOfWeek) { + view.mDayOfWeekLabelCalendar.set(Calendar.DAY_OF_WEEK, dayOfWeek); + SimpleMonthView_Delegate delegate = getDelegate(view); + if (delegate.mDayOfWeekFormatter == null) { + delegate.mDayOfWeekFormatter = + new SimpleDateFormat(DAY_OF_WEEK_FORMAT, getLocale(delegate, view)); + } + return delegate.mDayOfWeekFormatter.format(view.mDayOfWeekLabelCalendar.getTime()); + } + + private static Locale getLocale(SimpleMonthView_Delegate delegate, SimpleMonthView view) { + if (delegate.locale == null) { + delegate.locale = view.getContext().getResources().getConfiguration().locale; + } + return delegate.locale; + } + + @NonNull + private static SimpleMonthView_Delegate getDelegate(SimpleMonthView view) { + if (view == sLastView) { + assert sLastDelegate != null; + return sLastDelegate; + } else { + sLastView = view; + sLastDelegate = new SimpleMonthView_Delegate(); + return sLastDelegate; + } + } + + public static void clearCache() { + sLastView = null; + sLastDelegate = null; + } +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java index e589d9e70b8a..faaf1056bc9d 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java @@ -16,6 +16,8 @@ package com.android.layoutlib.bridge.android; +import com.android.layoutlib.bridge.impl.RenderAction; + import android.icu.util.ULocale; import java.util.Locale; @@ -56,4 +58,15 @@ public class AndroidLocale { public static String getScript(Locale locale) { return ULocale.forLocale(locale).getScript(); } + + public static Locale getDefault() { + BridgeContext context = RenderAction.getCurrentContext(); + if (context != null) { + Locale locale = context.getConfiguration().locale; + if (locale != null) { + return locale; + } + } + return Locale.getDefault(); + } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java index 9380ca798ee5..92b39e3f1b78 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java @@ -36,7 +36,9 @@ import android.util.DisplayMetrics; import android.view.ViewConfiguration_Accessor; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager_Accessor; +import android.widget.SimpleMonthView_Delegate; +import java.util.Locale; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; @@ -276,6 +278,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso mContext.getRenderResources().setLogger(null); } ParserFactory.setParserFactory(null); + SimpleMonthView_Delegate.clearCache(); } public static BridgeContext getCurrentContext() { @@ -397,6 +400,8 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso // preview releases of API 15. // TODO: Remove the try catch around Oct 2015. } + String locale = getParams().getLocale(); + if (locale != null && !locale.isEmpty()) config.locale = new Locale(locale); // TODO: fill in more config info. diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java index f6c2626e4271..8f0ad01c6dc3 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java @@ -77,6 +77,8 @@ public class AsmGenerator { /** Methods to inject. FQCN of class in which method should be injected => runnable that does * the injection. */ private final Map<String, ICreateInfo.InjectMethodRunnable> mInjectedMethodsMap; + /** A map { FQCN => set { field names } } which should be promoted to public visibility */ + private final Map<String, Set<String>> mPromotedFields; /** * Creates a new generator that can generate the output JAR with the stubbed classes. @@ -109,20 +111,8 @@ public class AsmGenerator { // Create the map/set of methods to change to delegates mDelegateMethods = new HashMap<String, Set<String>>(); - for (String signature : createInfo.getDelegateMethods()) { - int pos = signature.indexOf('#'); - if (pos <= 0 || pos >= signature.length() - 1) { - continue; - } - String className = binaryToInternalClassName(signature.substring(0, pos)); - String methodName = signature.substring(pos + 1); - Set<String> methods = mDelegateMethods.get(className); - if (methods == null) { - methods = new HashSet<String>(); - mDelegateMethods.put(className, methods); - } - methods.add(methodName); - } + addToMap(createInfo.getDelegateMethods(), mDelegateMethods); + for (String className : createInfo.getDelegateClassNatives()) { className = binaryToInternalClassName(className); Set<String> methods = mDelegateMethods.get(className); @@ -187,10 +177,34 @@ public class AsmGenerator { returnTypes.add(binaryToInternalClassName(className)); } + mPromotedFields = new HashMap<String, Set<String>>(); + addToMap(createInfo.getPromotedFields(), mPromotedFields); + mInjectedMethodsMap = createInfo.getInjectedMethodsMap(); } /** + * For each value in the array, split the value on '#' and add the parts to the map as key + * and value. + */ + private void addToMap(String[] entries, Map<String, Set<String>> map) { + for (String entry : entries) { + int pos = entry.indexOf('#'); + if (pos <= 0 || pos >= entry.length() - 1) { + return; + } + String className = binaryToInternalClassName(entry.substring(0, pos)); + String methodOrFieldName = entry.substring(pos + 1); + Set<String> set = map.get(className); + if (set == null) { + set = new HashSet<String>(); + map.put(className, set); + } + set.add(methodOrFieldName); + } + } + + /** * Returns the list of classes that have not been renamed yet. * <p/> * The names are "internal class names" rather than FQCN, i.e. they use "/" instead "." @@ -380,6 +394,10 @@ public class AsmGenerator { } } + Set<String> promoteFields = mPromotedFields.get(className); + if (promoteFields != null && !promoteFields.isEmpty()) { + cv = new PromoteFieldClassAdapter(cv, promoteFields); + } cr.accept(cv, 0); return cw.toByteArray(); } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index 499bea42007f..484240f49b20 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -120,6 +120,11 @@ public final class CreateInfo implements ICreateInfo { } @Override + public String[] getPromotedFields() { + return PROMOTED_FIELDS; + } + + @Override public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { return INJECTED_METHODS; } @@ -185,6 +190,8 @@ public final class CreateInfo implements ICreateInfo { "android.view.RenderNode#nSetElevation", "android.view.RenderNode#nGetElevation", "android.view.ViewGroup#drawChild", + "android.widget.SimpleMonthView#getTitle", + "android.widget.SimpleMonthView#getDayOfWeekLabel", "android.widget.TimePickerClockDelegate#getAmOrPmKeyCode", "com.android.internal.view.menu.MenuBuilder#createNewMenuItem", "com.android.internal.util.XmlUtils#convertValueToInt", @@ -289,6 +296,12 @@ public final class CreateInfo implements ICreateInfo { "org.kxml2.io.KXmlParser" }; + private final static String[] PROMOTED_FIELDS = new String[] { + "android.widget.SimpleMonthView#mTitle", + "android.widget.SimpleMonthView#mCalendar", + "android.widget.SimpleMonthView#mDayOfWeekLabelCalendar" + }; + /** * List of classes for which the methods returning them should be deleted. * The array contains a list of null terminated section starting with the name of the class diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java index 54b1fe628769..6c62423a2a89 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java @@ -78,6 +78,13 @@ public interface ICreateInfo { Set<String> getExcludedClasses(); /** + * Returns a list of fields which should be promoted to public visibility. The array values + * are in the form of the binary FQCN of the class containing the field and the field name + * separated by a '#'. + */ + String[] getPromotedFields(); + + /** * Returns a map from binary FQCN className to {@link InjectMethodRunnable} which will be * called to inject methods into a class. * Can be empty but must not be null. diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java new file mode 100644 index 000000000000..e4b70da2504f --- /dev/null +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 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 com.android.tools.layoutlib.create; + +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; + +import java.util.Set; + +import static org.objectweb.asm.Opcodes.ACC_PRIVATE; +import static org.objectweb.asm.Opcodes.ACC_PROTECTED; +import static org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static org.objectweb.asm.Opcodes.ASM4; + +/** + * Promotes given fields to public visibility. + */ +public class PromoteFieldClassAdapter extends ClassVisitor { + + private final Set<String> mFieldNames; + private static final int ACC_NOT_PUBLIC = ~(ACC_PRIVATE | ACC_PROTECTED); + + public PromoteFieldClassAdapter(ClassVisitor cv, Set<String> fieldNames) { + super(ASM4, cv); + mFieldNames = fieldNames; + } + + @Override + public FieldVisitor visitField(int access, String name, String desc, String signature, + Object value) { + if (mFieldNames.contains(name)) { + if ((access & ACC_PUBLIC) == 0) { + access = (access & ACC_NOT_PUBLIC) | ACC_PUBLIC; + } + } + return super.visitField(access, name, desc, signature, value); + } +} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java index 43691482dc66..0b85c48b4e68 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java @@ -93,18 +93,22 @@ public class ReplaceMethodCallsAdapter extends ClassVisitor { } }); - // Case 3: java.util.Locale.adjustLanguageCode() or java.util.Locale.forLanguageTag() + // Case 3: java.util.Locale.adjustLanguageCode() or java.util.Locale.forLanguageTag() or + // java.util.Locale.getDefault() METHOD_REPLACERS.add(new MethodReplacer() { private final String STRING_TO_STRING = Type.getMethodDescriptor(STRING, STRING); private final String STRING_TO_LOCALE = Type.getMethodDescriptor( Type.getType(Locale.class), STRING); + private final String VOID_TO_LOCALE = + Type.getMethodDescriptor(Type.getType(Locale.class)); @Override public boolean isNeeded(String owner, String name, String desc, String sourceClass) { return JAVA_LOCALE_CLASS.equals(owner) && ("adjustLanguageCode".equals(name) && desc.equals(STRING_TO_STRING) || - "forLanguageTag".equals(name) && desc.equals(STRING_TO_LOCALE)); + "forLanguageTag".equals(name) && desc.equals(STRING_TO_LOCALE) || + "getDefault".equals(name) && desc.equals(VOID_TO_LOCALE)); } @Override diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java index 2c21470d6a2f..8a2235b8526c 100644 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java +++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java @@ -138,6 +138,11 @@ public class AsmGeneratorTest { } @Override + public String[] getPromotedFields() { + return new String[0]; + } + + @Override public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { return new HashMap<String, InjectMethodRunnable>(0); } @@ -213,6 +218,11 @@ public class AsmGeneratorTest { } @Override + public String[] getPromotedFields() { + return new String[0]; + } + + @Override public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { return new HashMap<String, InjectMethodRunnable>(0); } @@ -296,6 +306,11 @@ public class AsmGeneratorTest { } @Override + public String[] getPromotedFields() { + return new String[0]; + } + + @Override public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { return new HashMap<String, InjectMethodRunnable>(0); } @@ -374,6 +389,11 @@ public class AsmGeneratorTest { } @Override + public String[] getPromotedFields() { + return new String[0]; + } + + @Override public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { HashMap<String, InjectMethodRunnable> map = new HashMap<String, InjectMethodRunnable>(1); |