diff options
Diffstat (limited to 'core/java/android')
56 files changed, 754 insertions, 295 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 7572799..e49acfa 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1545,6 +1545,24 @@ public class Activity extends ContextThemeWrapper } /** + * Ask to have the current assistant shown to the user. This only works if the calling + * activity is the current foreground activity. It is the same as calling + * {@link android.service.voice.VoiceInteractionService#showSession + * VoiceInteractionService.showSession} and requesting all of the possible context. + * The receiver will always see + * {@link android.service.voice.VoiceInteractionSession#SHOW_SOURCE_APPLICATION} set. + * @return Returns true if the assistant was successfully invoked, else false. For example + * false will be returned if the caller is not the current top activity. + */ + public boolean showAssist(Bundle args) { + try { + return ActivityManagerNative.getDefault().showAssistFromActivity(mToken, args); + } catch (RemoteException e) { + } + return false; + } + + /** * Called when you are no longer visible to the user. You will next * receive either {@link #onRestart}, {@link #onDestroy}, or nothing, * depending on later user activity. @@ -3771,6 +3789,11 @@ public class Activity extends ContextThemeWrapper /** * Callback for the result from requesting permissions. This method * is invoked for every call on {@link #requestPermissions(String[], int)}. + * <p> + * <strong>Note:</strong> It is possible that the permissions request interaction + * with the user is interrupted. In this case you will receive empty permissions + * and results arrays which should be treated as a cancellation. + * </p> * * @param requestCode The request code passed in {@link #requestPermissions(String[], int)}. * @param permissions The requested permissions. Never null. @@ -3977,16 +4000,24 @@ public class Activity extends ContextThemeWrapper * as intermediaries that dispatch their intent to the target the user selects -- to * do this, they must perform all security checks including permission grants as if * their launch had come from the original activity. + * @param intent The Intent to start. + * @param options ActivityOptions or null. + * @param ignoreTargetSecurity If true, the activity manager will not check whether the + * caller it is doing the start is, is actually allowed to start the target activity. + * If you set this to true, you must set an explicit component in the Intent and do any + * appropriate security checks yourself. + * @param userId The user the new activity should run as. * @hide */ - public void startActivityAsCaller(Intent intent, @Nullable Bundle options, int userId) { + public void startActivityAsCaller(Intent intent, @Nullable Bundle options, + boolean ignoreTargetSecurity, int userId) { if (mParent != null) { throw new RuntimeException("Can't be called from a child"); } Instrumentation.ActivityResult ar = mInstrumentation.execStartActivityAsCaller( this, mMainThread.getApplicationThread(), mToken, this, - intent, -1, options, userId); + intent, -1, options, ignoreTargetSecurity, userId); if (ar != null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, -1, ar.getResultCode(), diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 9ca206a..55b2fd9 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2807,7 +2807,7 @@ public class ActivityManager { /** * Request that the system start watching for the calling process to exceed a pss - * size as given here. Once called, the system will look for any occassions where it + * size as given here. Once called, the system will look for any occasions where it * sees the associated process with a larger pss size and, when this happens, automatically * pull a heap dump from it and allow the user to share the data. Note that this request * continues running even if the process is killed and restarted. To remove the watch, diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index fc408a8..b758a7a 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -206,9 +206,11 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM ? ProfilerInfo.CREATOR.createFromParcel(data) : null; Bundle options = data.readInt() != 0 ? Bundle.CREATOR.createFromParcel(data) : null; + boolean ignoreTargetSecurity = data.readInt() != 0; int userId = data.readInt(); int result = startActivityAsCaller(app, callingPackage, intent, resolvedType, - resultTo, resultWho, requestCode, startFlags, profilerInfo, options, userId); + resultTo, resultWho, requestCode, startFlags, profilerInfo, options, + ignoreTargetSecurity, userId); reply.writeNoException(); reply.writeInt(result); return true; @@ -2191,8 +2193,10 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM data.enforceInterface(IActivityManager.descriptor); int requestType = data.readInt(); IResultReceiver receiver = IResultReceiver.Stub.asInterface(data.readStrongBinder()); - requestAssistContextExtras(requestType, receiver); + IBinder activityToken = data.readStrongBinder(); + boolean res = requestAssistContextExtras(requestType, receiver, activityToken); reply.writeNoException(); + reply.writeInt(res ? 1 : 0); return true; } @@ -2223,7 +2227,17 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case IS_SCREEN_CAPTURE_ALLOWED_ON_CURRENT_ACTIVITY_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); - boolean res = isScreenCaptureAllowedOnCurrentActivity(); + boolean res = isAssistDataAllowedOnCurrentActivity(); + reply.writeNoException(); + reply.writeInt(res ? 1 : 0); + return true; + } + + case SHOW_ASSIST_FROM_ACTIVITY_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IBinder token = data.readStrongBinder(); + Bundle args = data.readBundle(); + boolean res = showAssistFromActivity(token, args); reply.writeNoException(); reply.writeInt(res ? 1 : 0); return true; @@ -2675,7 +2689,8 @@ class ActivityManagerProxy implements IActivityManager } public int startActivityAsCaller(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, - int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) throws RemoteException { + int startFlags, ProfilerInfo profilerInfo, Bundle options, boolean ignoreTargetSecurity, + int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -2699,6 +2714,7 @@ class ActivityManagerProxy implements IActivityManager } else { data.writeInt(0); } + data.writeInt(ignoreTargetSecurity ? 1 : 0); data.writeInt(userId); mRemote.transact(START_ACTIVITY_AS_CALLER_TRANSACTION, data, reply, 0); reply.readException(); @@ -5373,17 +5389,20 @@ class ActivityManagerProxy implements IActivityManager return res; } - public void requestAssistContextExtras(int requestType, IResultReceiver receiver) - throws RemoteException { + public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver, + IBinder activityToken) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeInt(requestType); data.writeStrongBinder(receiver.asBinder()); + data.writeStrongBinder(activityToken); mRemote.transact(REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0); reply.readException(); + boolean res = reply.readInt() != 0; data.recycle(); reply.recycle(); + return res; } public void reportAssistContextExtras(IBinder token, Bundle extras, AssistStructure structure, @@ -5425,7 +5444,7 @@ class ActivityManagerProxy implements IActivityManager return res; } - public boolean isScreenCaptureAllowedOnCurrentActivity() throws RemoteException { + public boolean isAssistDataAllowedOnCurrentActivity() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -5437,6 +5456,20 @@ class ActivityManagerProxy implements IActivityManager return res; } + public boolean showAssistFromActivity(IBinder token, Bundle args) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(token); + data.writeBundle(args); + mRemote.transact(SHOW_ASSIST_FROM_ACTIVITY_TRANSACTION, data, reply, 0); + reply.readException(); + boolean res = reply.readInt() != 0; + data.recycle(); + reply.recycle(); + return res; + } + public void killUid(int uid, String reason) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 08e1696..976830f 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -325,6 +325,12 @@ public class AppOpsManager { /** Write external storage. */ public static final String OPSTR_WRITE_EXTERNAL_STORAGE = "android:write_external_storage"; + /** Required to draw on top of other apps. */ + public static final String OPSTR_SYSTEM_ALERT_WINDOW + = "android:system_alert_window"; + /** Required to write/modify/update system settingss. */ + public static final String OPSTR_WRITE_SETTINGS + = "android:write_settings"; /** * This maps each operation to the operation that serves as the @@ -427,8 +433,8 @@ public class AppOpsManager { OPSTR_SEND_SMS, null, null, - null, - null, + OPSTR_WRITE_SETTINGS, + OPSTR_SYSTEM_ALERT_WINDOW, null, OPSTR_CAMERA, OPSTR_RECORD_AUDIO, diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java index 13030ca..84cbea9 100644 --- a/core/java/android/app/BackStackRecord.java +++ b/core/java/android/app/BackStackRecord.java @@ -1094,8 +1094,10 @@ final class BackStackRecord extends FragmentTransaction implements container.getViewTreeObserver().removeOnPreDrawListener(this); // Don't include any newly-hidden fragments in the transition. - excludeHiddenFragments(hiddenFragmentViews, inFragment.mContainerId, - overallTransition); + if (inFragment != null) { + excludeHiddenFragments(hiddenFragmentViews, inFragment.mContainerId, + overallTransition); + } ArrayMap<String, View> namedViews = null; if (sharedElementTransition != null) { @@ -1692,7 +1694,7 @@ final class BackStackRecord extends FragmentTransaction implements private static void setNameOverrides(TransitionState state, ArrayList<String> sourceNames, ArrayList<String> targetNames) { - if (sourceNames != null) { + if (sourceNames != null && targetNames != null) { for (int i = 0; i < sourceNames.size(); i++) { String source = sourceNames.get(i); String target = targetNames.get(i); @@ -1703,7 +1705,9 @@ final class BackStackRecord extends FragmentTransaction implements private void setBackNameOverrides(TransitionState state, ArrayMap<String, View> namedViews, boolean isEnd) { - int count = mSharedElementTargetNames == null ? 0 : mSharedElementTargetNames.size(); + int targetCount = mSharedElementTargetNames == null ? 0 : mSharedElementTargetNames.size(); + int sourceCount = mSharedElementSourceNames == null ? 0 : mSharedElementSourceNames.size(); + final int count = Math.min(targetCount, sourceCount); for (int i = 0; i < count; i++) { String source = mSharedElementSourceNames.get(i); String originalTarget = mSharedElementTargetNames.get(i); diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java index ad104a4..7fbb99a 100644 --- a/core/java/android/app/ExitTransitionCoordinator.java +++ b/core/java/android/app/ExitTransitionCoordinator.java @@ -25,6 +25,7 @@ import android.graphics.Matrix; import android.graphics.RectF; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -238,8 +239,12 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { if (decorView != null && decorView.getBackground() == null) { getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK)); } + final boolean targetsM = decorView == null || decorView.getContext() + .getApplicationInfo().targetSdkVersion >= VERSION_CODES.MNC; + ArrayList<String> sharedElementNames = targetsM ? mSharedElementNames : + mAllSharedElementNames; ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this, - mSharedElementNames, resultCode, data); + sharedElementNames, resultCode, data); mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() { @Override public void onTranslucentConversionComplete(boolean drawComplete) { diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 5490fe7..82206ea 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -1213,6 +1213,11 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene /** * Callback for the result from requesting permissions. This method * is invoked for every call on {@link #requestPermissions(String[], int)}. + * <p> + * <strong>Note:</strong> It is possible that the permissions request interaction + * with the user is interrupted. In this case you will receive empty permissions + * and results arrays which should be treated as a cancellation. + * </p> * * @param requestCode The request code passed in {@link #requestPermissions(String[], int)}. * @param permissions The requested permissions. Never null. @@ -1249,7 +1254,8 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public boolean shouldShowRequestPermissionRationale(@NonNull String permission) { if (mHost != null) { - mHost.getContext().getPackageManager().shouldShowRequestPermissionRationale(permission); + return mHost.getContext().getPackageManager() + .shouldShowRequestPermissionRationale(permission); } return false; } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 1d87d77..9ebbb9b 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -72,7 +72,8 @@ public interface IActivityManager extends IInterface { ProfilerInfo profilerInfo, Bundle options, int userId) throws RemoteException; public int startActivityAsCaller(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, - int flags, ProfilerInfo profilerInfo, Bundle options, int userId) throws RemoteException; + int flags, ProfilerInfo profilerInfo, Bundle options, boolean ignoreTargetSecurity, + int userId) throws RemoteException; public WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags, ProfilerInfo profilerInfo, Bundle options, @@ -433,8 +434,8 @@ public interface IActivityManager extends IInterface { public Bundle getAssistContextExtras(int requestType) throws RemoteException; - public void requestAssistContextExtras(int requestType, IResultReceiver receiver) - throws RemoteException; + public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver, + IBinder activityToken) throws RemoteException; public void reportAssistContextExtras(IBinder token, Bundle extras, AssistStructure structure, AssistContent content, Uri referrer) throws RemoteException; @@ -442,7 +443,9 @@ public interface IActivityManager extends IInterface { public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle, Bundle args) throws RemoteException; - public boolean isScreenCaptureAllowedOnCurrentActivity() throws RemoteException; + public boolean isAssistDataAllowedOnCurrentActivity() throws RemoteException; + + public boolean showAssistFromActivity(IBinder token, Bundle args) throws RemoteException; public void killUid(int uid, String reason) throws RemoteException; @@ -857,4 +860,5 @@ public interface IActivityManager extends IInterface { int UNREGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+298; int IS_SCREEN_CAPTURE_ALLOWED_ON_CURRENT_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+299; + int SHOW_ASSIST_FROM_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+300; } diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl index 8ab9ac3..474154b 100644 --- a/core/java/android/app/IUiAutomationConnection.aidl +++ b/core/java/android/app/IUiAutomationConnection.aidl @@ -38,10 +38,12 @@ interface IUiAutomationConnection { boolean injectInputEvent(in InputEvent event, boolean sync); boolean setRotation(int rotation); Bitmap takeScreenshot(int width, int height); - void shutdown(); boolean clearWindowContentFrameStats(int windowId); WindowContentFrameStats getWindowContentFrameStats(int windowId); void clearWindowAnimationFrameStats(); WindowAnimationFrameStats getWindowAnimationFrameStats(); void executeShellCommand(String command, in ParcelFileDescriptor fd); + + // Called from the system process. + oneway void shutdown(); } diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index 653f1b6..c2d901d 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -1701,7 +1701,8 @@ public class Instrumentation { */ public ActivityResult execStartActivityAsCaller( Context who, IBinder contextThread, IBinder token, Activity target, - Intent intent, int requestCode, Bundle options, int userId) { + Intent intent, int requestCode, Bundle options, boolean ignoreTargetSecurity, + int userId) { IApplicationThread whoThread = (IApplicationThread) contextThread; if (mActivityMonitors != null) { synchronized (mSync) { @@ -1725,7 +1726,7 @@ public class Instrumentation { .startActivityAsCaller(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, - requestCode, 0, null, options, userId); + requestCode, 0, null, options, ignoreTargetSecurity, userId); checkStartActivityResult(result, intent); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index c3dece8..fc71783 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -166,8 +166,10 @@ public class Notification implements Parcelable /** * The resource id of a drawable to use as the icon in the status bar. - * This is required; notifications with an invalid icon resource will not be shown. + * + * @deprecated Use {@link Builder#setSmallIcon(Icon)} instead. */ + @Deprecated @DrawableRes public int icon; @@ -269,8 +271,11 @@ public class Notification implements Parcelable public RemoteViews headsUpContentView; /** - * The bitmap that may escape the bounds of the panel and bar. + * A large bitmap to be shown in the notification content area. + * + * @deprecated Use {@link Builder#setLargeIcon(Icon)} instead. */ + @Deprecated public Bitmap largeIcon; /** @@ -900,11 +905,15 @@ public class Notification implements Parcelable */ public static class Action implements Parcelable { private final Bundle mExtras; + private Icon mIcon; private final RemoteInput[] mRemoteInputs; /** * Small icon representing the action. + * + * @deprecated Use {@link Action#getIcon()} instead. */ + @Deprecated public int icon; /** @@ -919,7 +928,12 @@ public class Notification implements Parcelable public PendingIntent actionIntent; private Action(Parcel in) { - icon = in.readInt(); + if (in.readInt() != 0) { + mIcon = Icon.CREATOR.createFromParcel(in); + } + if (mIcon.getType() == Icon.TYPE_RESOURCE) { + icon = mIcon.getResId(); + } title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); if (in.readInt() == 1) { actionIntent = PendingIntent.CREATOR.createFromParcel(in); @@ -929,15 +943,16 @@ public class Notification implements Parcelable } /** - * Use {@link Notification.Builder#addAction(int, CharSequence, PendingIntent)}. + * @deprecated Use {@link android.app.Notification.Action.Builder}. */ + @Deprecated public Action(int icon, CharSequence title, PendingIntent intent) { - this(icon, title, intent, new Bundle(), null); + this(Icon.createWithResource("", icon), title, intent, new Bundle(), null); } - private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras, + private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras, RemoteInput[] remoteInputs) { - this.icon = icon; + this.mIcon = icon; this.title = title; this.actionIntent = intent; this.mExtras = extras != null ? extras : new Bundle(); @@ -945,6 +960,17 @@ public class Notification implements Parcelable } /** + * Return an icon representing the action. + */ + public Icon getIcon() { + if (mIcon == null && icon != 0) { + // you snuck an icon in here without using the builder; let's try to keep it + mIcon = Icon.createWithResource("", icon); + } + return mIcon; + } + + /** * Get additional metadata carried around with this Action. */ public Bundle getExtras() { @@ -963,7 +989,7 @@ public class Notification implements Parcelable * Builder class for {@link Action} objects. */ public static final class Builder { - private final int mIcon; + private final Icon mIcon; private final CharSequence mTitle; private final PendingIntent mIntent; private final Bundle mExtras; @@ -975,7 +1001,18 @@ public class Notification implements Parcelable * @param title the title of the action * @param intent the {@link PendingIntent} to fire when users trigger this action */ + @Deprecated public Builder(int icon, CharSequence title, PendingIntent intent) { + this(Icon.createWithResource("", icon), title, intent, new Bundle(), null); + } + + /** + * Construct a new builder for {@link Action} object. + * @param icon icon to show for this action + * @param title the title of the action + * @param intent the {@link PendingIntent} to fire when users trigger this action + */ + public Builder(Icon icon, CharSequence title, PendingIntent intent) { this(icon, title, intent, new Bundle(), null); } @@ -985,11 +1022,11 @@ public class Notification implements Parcelable * @param action the action to read fields from. */ public Builder(Action action) { - this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras), + this(action.getIcon(), action.title, action.actionIntent, new Bundle(action.mExtras), action.getRemoteInputs()); } - private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras, + private Builder(Icon icon, CharSequence title, PendingIntent intent, Bundle extras, RemoteInput[] remoteInputs) { mIcon = icon; mTitle = title; @@ -1063,7 +1100,7 @@ public class Notification implements Parcelable @Override public Action clone() { return new Action( - icon, + getIcon(), title, actionIntent, // safe to alias new Bundle(mExtras), @@ -1075,7 +1112,13 @@ public class Notification implements Parcelable } @Override public void writeToParcel(Parcel out, int flags) { - out.writeInt(icon); + final Icon ic = getIcon(); + if (ic != null) { + out.writeInt(1); + ic.writeToParcel(out, 0); + } else { + out.writeInt(0); + } TextUtils.writeToParcel(title, out, flags); if (actionIntent != null) { out.writeInt(1); @@ -1819,6 +1862,9 @@ public class Notification implements Parcelable } else { sb.append("null"); } + if (this.tickerText != null) { + sb.append(" tick"); + } sb.append(" defaults=0x"); sb.append(Integer.toHexString(this.defaults)); sb.append(" flags=0x"); @@ -2725,7 +2771,10 @@ public class Notification implements Parcelable * @param icon Resource ID of a drawable that represents the action. * @param title Text describing the action. * @param intent PendingIntent to be fired when the action is invoked. + * + * @deprecated Use {@link #addAction(Action)} instead. */ + @Deprecated public Builder addAction(int icon, CharSequence title, PendingIntent intent) { mActions.add(new Action(icon, safeCharSequence(title), intent)); return this; @@ -3122,7 +3171,7 @@ public class Notification implements Parcelable private RemoteViews generateActionButton(Action action) { final boolean tombstone = (action.actionIntent == null); - RemoteViews button = new RemoteViews(mContext.getPackageName(), + RemoteViews button = new BuilderRemoteViews(mContext.getApplicationInfo(), tombstone ? getActionTombstoneLayoutResource() : getActionLayoutResource()); button.setTextViewCompoundDrawablesRelative(R.id.action0, action.icon, 0, 0, 0); @@ -4265,7 +4314,7 @@ public class Notification implements Parcelable * * In the expanded form, {@link Notification#bigContentView}, up to 5 * {@link Notification.Action}s specified with - * {@link Notification.Builder#addAction(int, CharSequence, PendingIntent) addAction} will be + * {@link Notification.Builder#addAction(Action) addAction} will be * shown as icon-only pushbuttons, suitable for transport controls. The Bitmap given to * {@link Notification.Builder#setLargeIcon(android.graphics.Bitmap) setLargeIcon()} will be * treated as album artwork. @@ -4391,7 +4440,7 @@ public class Notification implements Parcelable private RemoteViews generateMediaActionButton(Action action) { final boolean tombstone = (action.actionIntent == null); - RemoteViews button = new RemoteViews(mBuilder.mContext.getPackageName(), + RemoteViews button = new BuilderRemoteViews(mBuilder.mContext.getApplicationInfo(), R.layout.notification_material_media_action); button.setImageViewResource(R.id.action0, action.icon); button.setDrawableParameters(R.id.action0, false, -1, diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 10e8a53..01a1c18 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -691,6 +691,9 @@ final class SystemServiceRegistry { @Override public MidiManager createService(ContextImpl ctx) { IBinder b = ServiceManager.getService(Context.MIDI_SERVICE); + if (b == null) { + return null; + } return new MidiManager(IMidiManager.Stub.asInterface(b)); }}); diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java index 40126d6..ee0fc91 100644 --- a/core/java/android/app/assist/AssistStructure.java +++ b/core/java/android/app/assist/AssistStructure.java @@ -4,6 +4,7 @@ import android.app.Activity; import android.content.ComponentName; import android.graphics.Matrix; import android.graphics.Rect; +import android.os.BadParcelableException; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -31,8 +32,12 @@ public class AssistStructure implements Parcelable { static final String TAG = "AssistStructure"; static final boolean DEBUG_PARCEL = false; + static final boolean DEBUG_PARCEL_CHILDREN = false; static final boolean DEBUG_PARCEL_TREE = false; + static final int VALIDATE_WINDOW_TOKEN = 0x11111111; + static final int VALIDATE_VIEW_TOKEN = 0x22222222; + boolean mHaveData; ComponentName mActivityComponent; @@ -173,6 +178,26 @@ public class AssistStructure implements Parcelable { mCurViewStackEntry = entry; } + void writeView(ViewNode child, Parcel out, PooledStringWriter pwriter, int levelAdj) { + if (DEBUG_PARCEL) Log.d(TAG, "write view: at " + out.dataPosition() + + ", windows=" + mNumWrittenWindows + + ", views=" + mNumWrittenViews + + ", level=" + (mCurViewStackPos+levelAdj)); + out.writeInt(VALIDATE_VIEW_TOKEN); + int flags = child.writeSelfToParcel(out, pwriter, mTmpMatrix); + mNumWrittenViews++; + // If the child has children, push it on the stack to write them next. + if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) { + if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG, + "Preparing to write " + child.mChildren.length + + " children: @ #" + mNumWrittenViews + + ", level " + (mCurViewStackPos+levelAdj)); + out.writeInt(child.mChildren.length); + int pos = ++mCurViewStackPos; + pushViewStackEntry(child, pos); + } + } + boolean writeNextEntryToParcel(AssistStructure as, Parcel out, PooledStringWriter pwriter) { // Write next view node if appropriate. if (mCurViewStackEntry != null) { @@ -182,20 +207,7 @@ public class AssistStructure implements Parcelable { + mCurViewStackEntry.curChild + " in " + mCurViewStackEntry.node); ViewNode child = mCurViewStackEntry.node.mChildren[mCurViewStackEntry.curChild]; mCurViewStackEntry.curChild++; - if (DEBUG_PARCEL) Log.d(TAG, "write view: at " + out.dataPosition() - + ", windows=" + mNumWrittenWindows - + ", views=" + mNumWrittenViews); - out.writeInt(1); - int flags = child.writeSelfToParcel(out, pwriter, mTmpMatrix); - mNumWrittenViews++; - // If the child has children, push it on the stack to write them next. - if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) { - if (DEBUG_PARCEL_TREE) Log.d(TAG, "Preparing to write " - + child.mChildren.length + " children under " + child); - out.writeInt(child.mChildren.length); - int pos = ++mCurViewStackPos; - pushViewStackEntry(child, pos); - } + writeView(child, out, pwriter, 1); return true; } @@ -223,13 +235,13 @@ public class AssistStructure implements Parcelable { if (DEBUG_PARCEL) Log.d(TAG, "write window #" + pos + ": at " + out.dataPosition() + ", windows=" + mNumWrittenWindows + ", views=" + mNumWrittenViews); - out.writeInt(1); + out.writeInt(VALIDATE_WINDOW_TOKEN); win.writeSelfToParcel(out, pwriter, mTmpMatrix); mNumWrittenWindows++; ViewNode root = win.mRoot; mCurViewStackPos = 0; - if (DEBUG_PARCEL_TREE) Log.d(TAG, "Pushing initial root view " + root); - pushViewStackEntry(root, 0); + if (DEBUG_PARCEL_TREE) Log.d(TAG, "Writing initial root view " + root); + writeView(root, out, pwriter, 0); return true; } @@ -271,11 +283,16 @@ public class AssistStructure implements Parcelable { + ", views=" + mNumReadViews); } - Parcel readParcel() { + Parcel readParcel(int validateToken, int level) { if (DEBUG_PARCEL) Log.d(TAG, "readParcel: at " + mCurParcel.dataPosition() + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows - + ", views=" + mNumReadViews); - if (mCurParcel.readInt() != 0) { + + ", views=" + mNumReadViews + ", level=" + level); + int token = mCurParcel.readInt(); + if (token != 0) { + if (token != validateToken) { + throw new BadParcelableException("Got token " + Integer.toHexString(token) + + ", expected token " + Integer.toHexString(validateToken)); + } return mCurParcel; } // We have run out of partial data, need to read another batch. @@ -406,7 +423,7 @@ public class AssistStructure implements Parcelable { } WindowNode(ParcelTransferReader reader) { - Parcel in = reader.readParcel(); + Parcel in = reader.readParcel(VALIDATE_WINDOW_TOKEN, 0); reader.mNumReadWindows++; mX = in.readInt(); mY = in.readInt(); @@ -414,7 +431,7 @@ public class AssistStructure implements Parcelable { mHeight = in.readInt(); mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); mDisplayId = in.readInt(); - mRoot = new ViewNode(reader); + mRoot = new ViewNode(reader, 0); } void writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix) { @@ -548,8 +565,8 @@ public class AssistStructure implements Parcelable { ViewNode() { } - ViewNode(ParcelTransferReader reader) { - final Parcel in = reader.readParcel(); + ViewNode(ParcelTransferReader reader, int nestingLevel) { + final Parcel in = reader.readParcel(VALIDATE_VIEW_TOKEN, nestingLevel); reader.mNumReadViews++; final PooledStringReader preader = reader.mStringReader; mClassName = preader.readString(); @@ -604,9 +621,13 @@ public class AssistStructure implements Parcelable { } if ((flags&FLAGS_HAS_CHILDREN) != 0) { final int NCHILDREN = in.readInt(); + if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG, + "Preparing to read " + NCHILDREN + + " children: @ #" + reader.mNumReadViews + + ", level " + nestingLevel); mChildren = new ViewNode[NCHILDREN]; for (int i=0; i<NCHILDREN; i++) { - mChildren[i] = new ViewNode(reader); + mChildren[i] = new ViewNode(reader, nestingLevel + 1); } } } diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java index e09ab56..2ba8774 100644 --- a/core/java/android/bluetooth/le/BluetoothLeScanner.java +++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java @@ -79,6 +79,10 @@ public final class BluetoothLeScanner { * delivered through {@code callback}. * <p> * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. + * An app must hold + * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or + * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission + * in order to get results. * * @param callback Callback used to deliver scan results. * @throws IllegalArgumentException If {@code callback} is null. @@ -95,6 +99,10 @@ public final class BluetoothLeScanner { * Start Bluetooth LE scan. The scan results will be delivered through {@code callback}. * <p> * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. + * An app must hold + * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or + * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission + * in order to get results. * * @param filters {@link ScanFilter}s for finding exact BLE devices. * @param settings Settings for the scan. diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 3cc7684..ba9cf7c 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -16,8 +16,11 @@ package android.content; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.Manifest.permission.INTERACT_ACROSS_USERS; +import static android.app.AppOpsManager.MODE_ALLOWED; +import static android.app.AppOpsManager.MODE_ERRORED; +import static android.app.AppOpsManager.MODE_IGNORED; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import android.annotation.NonNull; import android.annotation.Nullable; @@ -40,8 +43,8 @@ import android.os.OperationCanceledException; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.UserHandle; -import android.util.Log; import android.text.TextUtils; +import android.util.Log; import java.io.File; import java.io.FileDescriptor; @@ -474,14 +477,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 { private int enforceReadPermission(String callingPkg, Uri uri, IBinder callerToken) throws SecurityException { - enforceReadPermissionInner(uri, callerToken); - - final int permOp = AppOpsManager.permissionToOpCode(mReadPermission); - if (permOp != AppOpsManager.OP_NONE) { - final int mode = mAppOpsManager.noteProxyOp(permOp, callingPkg); - if (mode != AppOpsManager.MODE_ALLOWED) { - return mode; - } + final int mode = enforceReadPermissionInner(uri, callingPkg, callerToken); + if (mode != MODE_ALLOWED) { + return mode; } if (mReadOp != AppOpsManager.OP_NONE) { @@ -493,14 +491,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 { private int enforceWritePermission(String callingPkg, Uri uri, IBinder callerToken) throws SecurityException { - enforceWritePermissionInner(uri, callerToken); - - final int permOp = AppOpsManager.permissionToOpCode(mWritePermission); - if (permOp != AppOpsManager.OP_NONE) { - final int mode = mAppOpsManager.noteProxyOp(permOp, callingPkg); - if (mode != AppOpsManager.MODE_ALLOWED) { - return mode; - } + final int mode = enforceWritePermissionInner(uri, callingPkg, callerToken); + if (mode != MODE_ALLOWED) { + return mode; } if (mWriteOp != AppOpsManager.OP_NONE) { @@ -518,26 +511,47 @@ public abstract class ContentProvider implements ComponentCallbacks2 { == PERMISSION_GRANTED; } + /** + * Verify that calling app holds both the given permission and any app-op + * associated with that permission. + */ + private int checkPermissionAndAppOp(String permission, String callingPkg, + IBinder callerToken) { + if (getContext().checkPermission(permission, Binder.getCallingPid(), Binder.getCallingUid(), + callerToken) != PERMISSION_GRANTED) { + return MODE_ERRORED; + } + + final int permOp = AppOpsManager.permissionToOpCode(permission); + if (permOp != AppOpsManager.OP_NONE) { + return mTransport.mAppOpsManager.noteProxyOp(permOp, callingPkg); + } + + return MODE_ALLOWED; + } + /** {@hide} */ - protected void enforceReadPermissionInner(Uri uri, IBinder callerToken) + protected int enforceReadPermissionInner(Uri uri, String callingPkg, IBinder callerToken) throws SecurityException { final Context context = getContext(); final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); String missingPerm = null; + int strongestMode = MODE_ALLOWED; if (UserHandle.isSameApp(uid, mMyUid)) { - return; + return MODE_ALLOWED; } if (mExported && checkUser(pid, uid, context)) { final String componentPerm = getReadPermission(); if (componentPerm != null) { - if (context.checkPermission(componentPerm, pid, uid, callerToken) - == PERMISSION_GRANTED) { - return; + final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, callerToken); + if (mode == MODE_ALLOWED) { + return MODE_ALLOWED; } else { missingPerm = componentPerm; + strongestMode = Math.max(strongestMode, mode); } } @@ -551,14 +565,15 @@ public abstract class ContentProvider implements ComponentCallbacks2 { for (PathPermission pp : pps) { final String pathPerm = pp.getReadPermission(); if (pathPerm != null && pp.match(path)) { - if (context.checkPermission(pathPerm, pid, uid, callerToken) - == PERMISSION_GRANTED) { - return; + final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, callerToken); + if (mode == MODE_ALLOWED) { + return MODE_ALLOWED; } else { // any denied <path-permission> means we lose // default <provider> access. allowDefaultRead = false; missingPerm = pathPerm; + strongestMode = Math.max(strongestMode, mode); } } } @@ -566,7 +581,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { // if we passed <path-permission> checks above, and no default // <provider> permission, then allow access. - if (allowDefaultRead) return; + if (allowDefaultRead) return MODE_ALLOWED; } // last chance, check against any uri grants @@ -575,7 +590,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 { ? maybeAddUserId(uri, callingUserId) : uri; if (context.checkUriPermission(userUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION, callerToken) == PERMISSION_GRANTED) { - return; + return MODE_ALLOWED; + } + + // If the worst denial we found above was ignored, then pass that + // ignored through; otherwise we assume it should be a real error below. + if (strongestMode == MODE_IGNORED) { + return MODE_IGNORED; } final String failReason = mExported @@ -587,25 +608,27 @@ public abstract class ContentProvider implements ComponentCallbacks2 { } /** {@hide} */ - protected void enforceWritePermissionInner(Uri uri, IBinder callerToken) + protected int enforceWritePermissionInner(Uri uri, String callingPkg, IBinder callerToken) throws SecurityException { final Context context = getContext(); final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); String missingPerm = null; + int strongestMode = MODE_ALLOWED; if (UserHandle.isSameApp(uid, mMyUid)) { - return; + return MODE_ALLOWED; } if (mExported && checkUser(pid, uid, context)) { final String componentPerm = getWritePermission(); if (componentPerm != null) { - if (context.checkPermission(componentPerm, pid, uid, callerToken) - == PERMISSION_GRANTED) { - return; + final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, callerToken); + if (mode == MODE_ALLOWED) { + return MODE_ALLOWED; } else { missingPerm = componentPerm; + strongestMode = Math.max(strongestMode, mode); } } @@ -619,14 +642,15 @@ public abstract class ContentProvider implements ComponentCallbacks2 { for (PathPermission pp : pps) { final String pathPerm = pp.getWritePermission(); if (pathPerm != null && pp.match(path)) { - if (context.checkPermission(pathPerm, pid, uid, callerToken) - == PERMISSION_GRANTED) { - return; + final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, callerToken); + if (mode == MODE_ALLOWED) { + return MODE_ALLOWED; } else { // any denied <path-permission> means we lose // default <provider> access. allowDefaultWrite = false; missingPerm = pathPerm; + strongestMode = Math.max(strongestMode, mode); } } } @@ -634,13 +658,19 @@ public abstract class ContentProvider implements ComponentCallbacks2 { // if we passed <path-permission> checks above, and no default // <provider> permission, then allow access. - if (allowDefaultWrite) return; + if (allowDefaultWrite) return MODE_ALLOWED; } // last chance, check against any uri grants if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, callerToken) == PERMISSION_GRANTED) { - return; + return MODE_ALLOWED; + } + + // If the worst denial we found above was ignored, then pass that + // ignored through; otherwise we assume it should be a real error below. + if (strongestMode == MODE_IGNORED) { + return MODE_IGNORED; } final String failReason = mExported diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 5571662..f786d2f 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1023,7 +1023,7 @@ public class Intent implements Parcelable, Cloneable { * * <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#MNC MNC} * and above and declares as using the {@link android.Manifest.permission#CALL_PHONE} - * permission which is not granted, then atempting to use this action will + * permission which is not granted, then attempting to use this action will * result in a {@link java.lang.SecurityException}. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index ceb610a..bc24d67 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -253,7 +253,7 @@ interface IPackageManager { List<PackageInfo> getPreferredPackages(int flags); - void resetPreferredActivities(int userId); + void resetApplicationPreferences(int userId); ResolveInfo getLastChosenActivity(in Intent intent, String resolvedType, int flags); diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index b7ee82d..9341be1 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -18,8 +18,10 @@ package android.content.pm; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.app.ActivityManager; import android.content.Context; import android.content.Intent; @@ -889,6 +891,8 @@ public class PackageInstaller { public String abiOverride; /** {@hide} */ public String volumeUuid; + /** {@hide} */ + public String[] grantedRuntimePermissions; /** * Construct parameters for a new package install session. @@ -914,6 +918,7 @@ public class PackageInstaller { referrerUri = source.readParcelable(null); abiOverride = source.readString(); volumeUuid = source.readString(); + grantedRuntimePermissions = source.readStringArray(); } /** @@ -987,6 +992,23 @@ public class PackageInstaller { this.referrerUri = referrerUri; } + /** + * Sets which runtime permissions to be granted to the package at installation. + * Using this API requires holding {@link android.Manifest.permission + * #INSTALL_GRANT_RUNTIME_PERMISSIONS} + * + * @param permissions The permissions to grant or null to grant all runtime + * permissions. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) + public void setGrantedRuntimePermissions(String[] permissions) { + installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS; + this.grantedRuntimePermissions = permissions; + } + /** {@hide} */ public void setInstallFlagsInternal() { installFlags |= PackageManager.INSTALL_INTERNAL; @@ -1012,6 +1034,7 @@ public class PackageInstaller { pw.printPair("referrerUri", referrerUri); pw.printPair("abiOverride", abiOverride); pw.printPair("volumeUuid", volumeUuid); + pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions); pw.println(); } @@ -1033,6 +1056,7 @@ public class PackageInstaller { dest.writeParcelable(referrerUri, flags); dest.writeString(abiOverride); dest.writeString(volumeUuid); + dest.writeStringArray(grantedRuntimePermissions); } public static final Parcelable.Creator<SessionParams> diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 6533bbc..cda5816 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1514,6 +1514,13 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device has biometric hardware to detect a fingerprint. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device supports portrait orientation * screens. For backwards compatibility, you can assume that if neither * this nor {@link #FEATURE_SCREEN_LANDSCAPE} is set then the device supports diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java index 2828d83..d514513 100644 --- a/core/java/android/content/pm/PermissionInfo.java +++ b/core/java/android/content/pm/PermissionInfo.java @@ -145,12 +145,10 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_COSTS_MONEY = 1<<0; /** - * Flag for {@link #protectionLevel}, corresponding - * to the <code>hide</code> value of - * {@link android.R.attr#permissionFlags}. - * @hide + * Flag for {@link #flags}, indicating that this permission has been + * installed into the system's globally defined permissions. */ - public static final int PROTECTION_FLAG_HIDE = 1<<1; + public static final int FLAG_INSTALLED = 1<<30; /** * Additional flags about this permission as given by @@ -210,6 +208,15 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { if ((level&PermissionInfo.PROTECTION_FLAG_PRE23) != 0) { protLevel += "|pre23"; } + if ((level&PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0) { + protLevel += "|installer"; + } + if ((level&PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0) { + protLevel += "|verifier"; + } + if ((level&PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0) { + protLevel += "|preinstalled"; + } return protLevel; } diff --git a/core/java/android/content/res/DrawableCache.java b/core/java/android/content/res/DrawableCache.java index fc70bc6..ba00134 100644 --- a/core/java/android/content/res/DrawableCache.java +++ b/core/java/android/content/res/DrawableCache.java @@ -52,6 +52,6 @@ class DrawableCache extends ThemedResourceCache<Drawable.ConstantState> { @Override public boolean shouldInvalidateEntry(Drawable.ConstantState entry, int configChanges) { - return false; + return Configuration.needNewResources(configChanges, entry.getChangingConfigurations()); } } diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java index 46cafad..46ffe36 100644 --- a/core/java/android/hardware/camera2/CameraCaptureSession.java +++ b/core/java/android/hardware/camera2/CameraCaptureSession.java @@ -138,6 +138,45 @@ public abstract class CameraCaptureSession implements AutoCloseable { */ public abstract void prepare(@NonNull Surface surface) throws CameraAccessException; + + /** + * <p>Free all buffers allocated for an output Surface.</p> + * + * <p>Normally, once allocated, the image buffers for a given output Surface remain allocated + * for the lifetime of the capture session, to minimize latency of captures and to reduce + * memory allocation overhead.</p> + * + * <p>However, in some cases, it may be desirable for allocated buffers to be freed to reduce + * the application's memory consumption, if the particular output Surface will not be used by + * the application for some time.</p> + * + * <p>The tearDown() method can be used to perform this operation. After the call finishes, all + * unfilled image buffers will have been freed. Any future use of the target Surface may require + * allocation of additional buffers, as if the session had just been created. Buffers being + * held by the application (either explicitly as Image objects from ImageReader, or implicitly + * as the current texture in a SurfaceTexture or the current contents of a RS Allocation, will + * remain valid and allocated even when tearDown is invoked.</p> + * + * <p>A Surface that has had tearDown() called on it is eligible to have prepare() invoked on it + * again even if it was used as a request target before the tearDown() call, as long as it + * doesn't get used as a target of a request between the tearDown() and prepare() calls.</p> + * + * @param surface the output Surface for which buffers should be freed. Must be one of the + * the output Surfaces used to create this session. + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error. + * @throws IllegalStateException if this session is no longer active, either because the session + * was explicitly closed, a new session has been created + * or the camera device has been closed. + * @throws IllegalArgumentException if the Surface is invalid, not part of this Session, or has + * already been used as a target of a CaptureRequest in this + * session or immediately prior sessions. + * + * @hide + */ + public abstract void tearDown(@NonNull Surface surface) throws CameraAccessException; + /** * <p>Submit a request for an image to be captured by the camera device.</p> * diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index c36683b..af1367c 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -1994,8 +1994,9 @@ public abstract class CameraMetadata<TKey> { public static final int EDGE_MODE_OFF = 0; /** - * <p>Apply edge enhancement at a quality level that does not slow down frame rate relative to sensor - * output</p> + * <p>Apply edge enhancement at a quality level that does not slow down frame rate + * relative to sensor output. It may be the same as OFF if edge enhancement will + * slow down frame rate relative to sensor.</p> * @see CaptureRequest#EDGE_MODE */ public static final int EDGE_MODE_FAST = 1; @@ -2117,7 +2118,8 @@ public abstract class CameraMetadata<TKey> { /** * <p>Noise reduction is applied without reducing frame rate relative to sensor - * output.</p> + * output. It may be the same as OFF if noise reduction will reduce frame rate + * relative to sensor.</p> * @see CaptureRequest#NOISE_REDUCTION_MODE */ public static final int NOISE_REDUCTION_MODE_FAST = 1; diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index a136d0f..e965d65 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -1584,8 +1584,9 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * will be applied. HIGH_QUALITY mode indicates that the * camera device will use the highest-quality enhancement algorithms, * even if it slows down capture rate. FAST means the camera device will - * not slow down capture rate when applying edge enhancement. Every output stream will - * have a similar amount of enhancement applied.</p> + * not slow down capture rate when applying edge enhancement. FAST may be the same as OFF if + * edge enhancement will slow down capture rate. Every output stream will have a similar + * amount of enhancement applied.</p> * <p>ZERO_SHUTTER_LAG is meant to be used by applications that maintain a continuous circular * buffer of high-resolution images during preview and reprocess image(s) from that buffer * into a final capture when triggered by the user. In this mode, the camera device applies @@ -1594,7 +1595,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * since those will be reprocessed later if necessary.</p> * <p>For YUV_REPROCESSING, these FAST/HIGH_QUALITY modes both mean that the camera * device will apply FAST/HIGH_QUALITY YUV-domain edge enhancement, respectively. - * The camera device may adjust its internal noise reduction parameters for best + * The camera device may adjust its internal edge enhancement parameters for best * image quality based on the {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor}, if it is set.</p> * <p><b>Possible values:</b> * <ul> @@ -2003,8 +2004,9 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * will be applied. HIGH_QUALITY mode indicates that the camera device * will use the highest-quality noise filtering algorithms, * even if it slows down capture rate. FAST means the camera device will not - * slow down capture rate when applying noise filtering. Every output stream will - * have a similar amount of enhancement applied.</p> + * slow down capture rate when applying noise filtering. FAST may be the same as MINIMAL if + * MINIMAL is listed, or the same as OFF if any noise filtering will slow down capture rate. + * Every output stream will have a similar amount of enhancement applied.</p> * <p>ZERO_SHUTTER_LAG is meant to be used by applications that maintain a continuous circular * buffer of high-resolution images during preview and reprocess image(s) from that buffer * into a final capture when triggered by the user. In this mode, the camera device applies diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index f7cf185..d5511c1 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -2095,8 +2095,9 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * will be applied. HIGH_QUALITY mode indicates that the * camera device will use the highest-quality enhancement algorithms, * even if it slows down capture rate. FAST means the camera device will - * not slow down capture rate when applying edge enhancement. Every output stream will - * have a similar amount of enhancement applied.</p> + * not slow down capture rate when applying edge enhancement. FAST may be the same as OFF if + * edge enhancement will slow down capture rate. Every output stream will have a similar + * amount of enhancement applied.</p> * <p>ZERO_SHUTTER_LAG is meant to be used by applications that maintain a continuous circular * buffer of high-resolution images during preview and reprocess image(s) from that buffer * into a final capture when triggered by the user. In this mode, the camera device applies @@ -2105,7 +2106,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * since those will be reprocessed later if necessary.</p> * <p>For YUV_REPROCESSING, these FAST/HIGH_QUALITY modes both mean that the camera * device will apply FAST/HIGH_QUALITY YUV-domain edge enhancement, respectively. - * The camera device may adjust its internal noise reduction parameters for best + * The camera device may adjust its internal edge enhancement parameters for best * image quality based on the {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor}, if it is set.</p> * <p><b>Possible values:</b> * <ul> @@ -2786,8 +2787,9 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * will be applied. HIGH_QUALITY mode indicates that the camera device * will use the highest-quality noise filtering algorithms, * even if it slows down capture rate. FAST means the camera device will not - * slow down capture rate when applying noise filtering. Every output stream will - * have a similar amount of enhancement applied.</p> + * slow down capture rate when applying noise filtering. FAST may be the same as MINIMAL if + * MINIMAL is listed, or the same as OFF if any noise filtering will slow down capture rate. + * Every output stream will have a similar amount of enhancement applied.</p> * <p>ZERO_SHUTTER_LAG is meant to be used by applications that maintain a continuous circular * buffer of high-resolution images during preview and reprocess image(s) from that buffer * into a final capture when triggered by the user. In this mode, the camera device applies diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl index 1574f93..7cb3673 100644 --- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl +++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl @@ -100,4 +100,6 @@ interface ICameraDeviceUser int flush(out LongParcelable lastFrameNumber); int prepare(int streamId); + + int tearDown(int streamId); } diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java index 3c19cd2..d325c77 100644 --- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java @@ -146,6 +146,11 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession } @Override + public void tearDown(Surface surface) throws CameraAccessException { + mDeviceImpl.tearDown(surface); + } + + @Override public synchronized int capture(CaptureRequest request, CaptureCallback callback, Handler handler) throws CameraAccessException { if (request == null) { diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java index d732535..a920e2b 100644 --- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java @@ -169,6 +169,11 @@ public class CameraConstrainedHighSpeedCaptureSessionImpl } @Override + public void tearDown(Surface surface) throws CameraAccessException { + mSessionImpl.tearDown(surface); + } + + @Override public int capture(CaptureRequest request, CaptureCallback listener, Handler handler) throws CameraAccessException { throw new UnsupportedOperationException("Constrained high speed session doesn't support" diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index c594228..91d623e 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -679,6 +679,31 @@ public class CameraDeviceImpl extends CameraDevice { } } + public void tearDown(Surface surface) throws CameraAccessException { + if (surface == null) throw new IllegalArgumentException("Surface is null"); + + synchronized(mInterfaceLock) { + int streamId = -1; + for (int i = 0; i < mConfiguredOutputs.size(); i++) { + if (surface == mConfiguredOutputs.valueAt(i).getSurface()) { + streamId = mConfiguredOutputs.keyAt(i); + break; + } + } + if (streamId == -1) { + throw new IllegalArgumentException("Surface is not part of this session"); + } + try { + mRemoteDevice.tearDown(streamId); + } catch (CameraRuntimeException e) { + throw e.asChecked(); + } catch (RemoteException e) { + // impossible + return; + } + } + } + public int capture(CaptureRequest request, CaptureCallback callback, Handler handler) throws CameraAccessException { if (DEBUG) { diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java index f5314da..e20eaa7 100644 --- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java +++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java @@ -636,6 +636,20 @@ public class CameraDeviceUserShim implements ICameraDeviceUser { return CameraBinderDecorator.NO_ERROR; } + public int tearDown(int streamId) { + if (DEBUG) { + Log.d(TAG, "tearDown called."); + } + if (mLegacyDevice.isClosed()) { + Log.e(TAG, "Cannot tear down stream, device has been closed."); + return CameraBinderDecorator.ENODEV; + } + + // LEGACY doesn't support actual teardown, so just a no-op + + return CameraBinderDecorator.NO_ERROR; + } + @Override public IBinder asBinder() { // This is solely intended to be used for in-process binding. diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index c5f142a..ee37047 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -321,6 +321,14 @@ public class FingerprintManager { * Called when a fingerprint is valid but not recognized. */ public void onAuthenticationFailed() { } + + /** + * Called when a fingerprint image has been acquired, but wasn't processed yet. + * + * @param acquireInfo one of FINGERPRINT_ACQUIRED_* constants + * @hide + */ + public void onAuthenticationAcquired(int acquireInfo) {} }; /** @@ -737,9 +745,13 @@ public class FingerprintManager { } private void sendAcquiredResult(long deviceId, int acquireInfo) { + if (mAuthenticationCallback != null) { + mAuthenticationCallback.onAuthenticationAcquired(acquireInfo); + } final String msg = getAcquiredString(acquireInfo); - if (msg == null) return; - + if (msg == null) { + return; + } if (mEnrollmentCallback != null) { mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg); } else if (mAuthenticationCallback != null) { diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java index b039fc7..a2c1d18 100644 --- a/core/java/android/inputmethodservice/ExtractEditText.java +++ b/core/java/android/inputmethodservice/ExtractEditText.java @@ -103,8 +103,12 @@ public class ExtractEditText extends EditText { } @Override public boolean onTextContextMenuItem(int id) { - // Select all shouldn't be handled by the original edit text, but by the extracted one. - if (id != android.R.id.selectAll && mIME != null && mIME.onExtractTextContextMenuItem(id)) { + // Select all and Replace text shouldn't be handled by the original edit text, but by the + // extracted one. + if (id == android.R.id.selectAll || id == android.R.id.replaceText) { + return super.onTextContextMenuItem(id); + } + if (mIME != null && mIME.onExtractTextContextMenuItem(id)) { // Mode was started on Extracted, needs to be stopped here. // Cut will change the text, which stops selection mode. if (id == android.R.id.copy || id == android.R.id.paste) stopTextActionMode(); diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 864225a..af4c2bc 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -16,6 +16,7 @@ package android.os; +import android.annotation.NonNull; import android.provider.DocumentsContract.Document; import android.system.ErrnoException; import android.system.Os; @@ -69,6 +70,8 @@ public class FileUtils { /** Regular expression for safe filenames: no spaces or metacharacters */ private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+"); + private static final File[] EMPTY = new File[0]; + /** * Set owner and mode of of given {@link File}. * @@ -634,4 +637,13 @@ public class FileUtils { return new File(parent, name + "." + ext); } } + + public static @NonNull File[] listFilesOrEmpty(File dir) { + File[] res = dir.listFiles(); + if (res != null) { + return res; + } else { + return EMPTY; + } + } } diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl index b768852..d3eec1e 100644 --- a/core/java/android/os/IDeviceIdleController.aidl +++ b/core/java/android/os/IDeviceIdleController.aidl @@ -29,5 +29,6 @@ interface IDeviceIdleController { boolean isPowerSaveWhitelistApp(String name); void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason); long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason); + long addPowerSaveTempWhitelistAppForSms(String name, int userId, String reason); void exitIdle(String reason); } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index b104135..79fb805 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -45,7 +45,9 @@ public class UserManager { private final Context mContext; /** - * Specifies if a user is disallowed from adding and removing accounts. + * Specifies if a user is disallowed from adding and removing accounts, unless they are + * {@link android.accounts.AccountManager#addAccountExplicitly programmatically} added by + * Authenticator. * The default value is <code>false</code>. * * <p/>Key for user restrictions. diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java index d743484..aa22041 100644 --- a/core/java/android/provider/CalendarContract.java +++ b/core/java/android/provider/CalendarContract.java @@ -2393,7 +2393,7 @@ public final class CalendarContract { intent.setData(ContentUris.withAppendedId(CalendarContract.CONTENT_URI, alarmTime)); intent.putExtra(ALARM_TIME, alarmTime); PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0); - manager.setExact(AlarmManager.RTC_WAKEUP, alarmTime, pi); + manager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTime, pi); } /** diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index d547a60..8ce1cbf 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -5957,9 +5957,7 @@ public final class ContactsContract { */ public static final CharSequence getTypeLabel(Resources res, int type, CharSequence label) { - if (type == TYPE_CUSTOM) { - return (label != null ? label : ""); - } else if (type == TYPE_ASSISTANT && !TextUtils.isEmpty(label)) { + if ((type == TYPE_CUSTOM || type == TYPE_ASSISTANT) && !TextUtils.isEmpty(label)) { return label; } else { final int labelRes = getTypeLabelResource(type); diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 6979bee..5a341fc 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -640,7 +640,7 @@ public abstract class DocumentsProvider extends ContentProvider { final Bundle out = new Bundle(); try { if (METHOD_CREATE_DOCUMENT.equals(method)) { - enforceWritePermissionInner(documentUri, null); + enforceWritePermissionInner(documentUri, getCallingPackage(), null); final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE); final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME); @@ -654,7 +654,7 @@ public abstract class DocumentsProvider extends ContentProvider { out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri); } else if (METHOD_RENAME_DOCUMENT.equals(method)) { - enforceWritePermissionInner(documentUri, null); + enforceWritePermissionInner(documentUri, getCallingPackage(), null); final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME); final String newDocumentId = renameDocument(documentId, displayName); @@ -678,7 +678,7 @@ public abstract class DocumentsProvider extends ContentProvider { } } else if (METHOD_DELETE_DOCUMENT.equals(method)) { - enforceWritePermissionInner(documentUri, null); + enforceWritePermissionInner(documentUri, getCallingPackage(), null); deleteDocument(documentId); // Document no longer exists, clean up any grants diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index fff355b..a79970c 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7578,14 +7578,6 @@ public final class Settings { public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled"; /** - * Global override to disable VoLTE (independent of user setting) - * <p> - * Type: int (1 for disable VoLTE, 0 to use user configuration) - * @hide - */ - public static final String VOLTE_FEATURE_DISABLED = "volte_feature_disabled"; - - /** * Whether user can enable/disable LTE as a preferred network. A carrier might control * this via gservices, OMA-DM, carrier app, etc. * <p> diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java index e1b5a6d..76eaea9 100644 --- a/core/java/android/provider/VoicemailContract.java +++ b/core/java/android/provider/VoicemailContract.java @@ -314,11 +314,16 @@ public class VoicemailContract { contentValues.put(Voicemails.IS_READ, voicemail.isRead() ? 1 : 0); PhoneAccountHandle phoneAccount = voicemail.getPhoneAccount(); - if (voicemail.getPhoneAccount() != null) { + if (phoneAccount != null) { contentValues.put(Voicemails.PHONE_ACCOUNT_COMPONENT_NAME, phoneAccount.getComponentName().flattenToString()); contentValues.put(Voicemails.PHONE_ACCOUNT_ID, phoneAccount.getId()); } + + if (voicemail.getTranscription() != null) { + contentValues.put(Voicemails.TRANSCRIPTION, voicemail.getTranscription()); + } + return contentValues; } } diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index bae5455..04d5952 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -51,6 +51,7 @@ public final class KeymasterDefs { public static final int KM_TAG_DIGEST = KM_ENUM_REP | 5; public static final int KM_TAG_PADDING = KM_ENUM_REP | 6; public static final int KM_TAG_CALLER_NONCE = KM_BOOL | 7; + public static final int KM_TAG_MIN_MAC_LENGTH = KM_UINT | 8; public static final int KM_TAG_RESCOPING_ADD = KM_ENUM_REP | 101; public static final int KM_TAG_RESCOPING_DEL = KM_ENUM_REP | 102; @@ -194,6 +195,9 @@ public final class KeymasterDefs { public static final int KM_ERROR_KEY_RATE_LIMIT_EXCEEDED = -54; public static final int KM_ERROR_CALLER_NONCE_PROHIBITED = -55; public static final int KM_ERROR_KEY_MAX_OPS_EXCEEDED = -56; + public static final int KM_ERROR_INVALID_MAC_LENGTH = -57; + public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58; + public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59; public static final int KM_ERROR_UNIMPLEMENTED = -100; public static final int KM_ERROR_VERSION_MISMATCH = -101; public static final int KM_ERROR_UNKNOWN_ERROR = -1000; @@ -237,6 +241,8 @@ public final class KeymasterDefs { sErrorCodeToString.put(KM_ERROR_INVALID_NONCE, "Invalid IV"); sErrorCodeToString.put(KM_ERROR_CALLER_NONCE_PROHIBITED, "Caller-provided IV not permitted"); + sErrorCodeToString.put(KM_ERROR_INVALID_MAC_LENGTH, + "Invalid MAC or authentication tag length"); sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented"); sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error"); } diff --git a/core/java/android/service/chooser/ChooserTarget.java b/core/java/android/service/chooser/ChooserTarget.java index 50c435a..c2f70cc 100644 --- a/core/java/android/service/chooser/ChooserTarget.java +++ b/core/java/android/service/chooser/ChooserTarget.java @@ -17,20 +17,14 @@ package android.service.chooser; -import android.app.Activity; -import android.app.PendingIntent; +import android.annotation.Nullable; import android.content.ComponentName; -import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.IntentSender; -import android.graphics.Bitmap; import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import android.os.UserHandle; -import android.util.Log; /** * A ChooserTarget represents a deep-link into an application as returned by a @@ -62,52 +56,21 @@ public final class ChooserTarget implements Parcelable { private Icon mIcon; /** - * The IntentSender that will be used to deliver the intent to the target. - * It will be {@link android.content.Intent#fillIn(android.content.Intent, int)} filled in} - * by the real intent sent by the application. + * The ComponentName of the Activity to be invoked. Must be part of the target creator's + * own package or an Activity exported by its package. */ - private IntentSender mIntentSender; + private ComponentName mComponentName; /** - * The score given to this item. It can be normalized. + * A Bundle to merge with the extras of the intent sent to this target. + * Any extras here will override the extras from the original intent. */ - private float mScore; + private Bundle mIntentExtras; /** - * Construct a deep link target for presentation by a chooser UI. - * - * <p>A target is composed of a title and an icon for presentation to the user. - * The UI presenting this target may truncate the title if it is too long to be presented - * in the available space, as well as crop, resize or overlay the supplied icon.</p> - * - * <p>The creator of a target may supply a ranking score. This score is assumed to be relative - * to the other targets supplied by the same - * {@link ChooserTargetService#onGetChooserTargets(ComponentName, IntentFilter) query}. - * Scores should be in the range from 0.0f (unlikely match) to 1.0f (very relevant match). - * Scores for a set of targets do not need to sum to 1.</p> - * - * <p>Before being sent, the PendingIntent supplied will be - * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied - * to the chooser. When constructing a PendingIntent for use in a ChooserTarget, make sure - * that you permit the relevant fields to be filled in using the appropriate flags such as - * {@link Intent#FILL_IN_ACTION}, {@link Intent#FILL_IN_CATEGORIES}, - * {@link Intent#FILL_IN_DATA} and {@link Intent#FILL_IN_CLIP_DATA}. Note that - * {@link Intent#FILL_IN_CLIP_DATA} is required to appropriately receive URI permission grants - * for {@link Intent#ACTION_SEND} intents.</p> - * - * <p>Take care not to place custom {@link android.os.Parcelable} types into - * the PendingIntent as extras, as the system will not be able to unparcel it to merge - * additional extras.</p> - * - * @param title title of this target that will be shown to a user - * @param icon icon to represent this target - * @param score ranking score for this target between 0.0f and 1.0f, inclusive - * @param pendingIntent PendingIntent to fill in and send if the user chooses this target + * The score given to this item. It can be normalized. */ - public ChooserTarget(CharSequence title, Icon icon, float score, - PendingIntent pendingIntent) { - this(title, icon, score, pendingIntent.getIntentSender()); - } + private float mScore; /** * Construct a deep link target for presentation by a chooser UI. @@ -122,25 +85,23 @@ public final class ChooserTarget implements Parcelable { * Scores should be in the range from 0.0f (unlikely match) to 1.0f (very relevant match). * Scores for a set of targets do not need to sum to 1.</p> * - * <p>Before being sent, the IntentSender supplied will be - * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied - * to the chooser. When constructing an IntentSender for use in a ChooserTarget, make sure - * that you permit the relevant fields to be filled in using the appropriate flags such as - * {@link Intent#FILL_IN_ACTION}, {@link Intent#FILL_IN_CATEGORIES}, - * {@link Intent#FILL_IN_DATA} and {@link Intent#FILL_IN_CLIP_DATA}. Note that - * {@link Intent#FILL_IN_CLIP_DATA} is required to appropriately receive URI permission grants - * for {@link Intent#ACTION_SEND} intents.</p> + * <p>The ComponentName must be the name of an Activity component in the creator's own + * package, or an exported component from any other package. You may provide an optional + * Bundle of extras that will be merged into the final intent before it is sent to the + * target Activity; use this to add any additional data about the deep link that the target + * activity will read. e.g. conversation IDs, email addresses, etc.</p> * * <p>Take care not to place custom {@link android.os.Parcelable} types into - * the IntentSender as extras, as the system will not be able to unparcel it to merge - * additional extras.</p> + * the extras bundle, as the system will not be able to unparcel them to merge them.</p> * * @param title title of this target that will be shown to a user * @param icon icon to represent this target * @param score ranking score for this target between 0.0f and 1.0f, inclusive - * @param intentSender IntentSender to fill in and send if the user chooses this target + * @param componentName Name of the component to be launched if this target is chosen + * @param intentExtras Bundle of extras to merge with the extras of the launched intent */ - public ChooserTarget(CharSequence title, Icon icon, float score, IntentSender intentSender) { + public ChooserTarget(CharSequence title, Icon icon, float score, + ComponentName componentName, @Nullable Bundle intentExtras) { mTitle = title; mIcon = icon; if (score > 1.f || score < 0.f) { @@ -148,7 +109,8 @@ public final class ChooserTarget implements Parcelable { + "must be between 0.0f and 1.0f"); } mScore = score; - mIntentSender = intentSender; + mComponentName = componentName; + mIntentExtras = intentExtras; } ChooserTarget(Parcel in) { @@ -159,7 +121,8 @@ public final class ChooserTarget implements Parcelable { mIcon = null; } mScore = in.readFloat(); - mIntentSender = IntentSender.readIntentSenderOrNullFromParcel(in); + mComponentName = ComponentName.readFromParcel(in); + mIntentExtras = in.readBundle(); } /** @@ -194,49 +157,29 @@ public final class ChooserTarget implements Parcelable { } /** - * Returns the raw IntentSender supplied by the ChooserTarget's creator. - * This may be null if the creator specified a regular Intent instead. - * - * <p>To fill in and send the intent, see {@link #sendIntent(Context, Intent)}.</p> + * Returns the ComponentName of the Activity that should be launched for this ChooserTarget. * - * @return the IntentSender supplied by the ChooserTarget's creator + * @return the name of the target Activity to launch */ - public IntentSender getIntentSender() { - return mIntentSender; + public ComponentName getComponentName() { + return mComponentName; } /** - * Fill in the IntentSender supplied by the ChooserTarget's creator and send it. + * Returns the Bundle of extras to be added to an intent launched to this target. * - * @param context the sending Context; generally the Activity presenting the chooser UI - * @param fillInIntent the Intent provided to the Chooser to be sent to a selected target - * @return true if sending the Intent was successful + * @return the extras to merge with the extras of the intent being launched */ - public boolean sendIntent(Context context, Intent fillInIntent) { - if (fillInIntent != null) { - fillInIntent.migrateExtraStreamToClipData(); - fillInIntent.prepareToLeaveProcess(); - } - if (mIntentSender != null) { - try { - mIntentSender.sendIntent(context, 0, fillInIntent, null, null); - return true; - } catch (IntentSender.SendIntentException e) { - Log.e(TAG, "sendIntent " + this + " failed", e); - return false; - } - } else { - Log.e(TAG, "sendIntent " + this + " failed - no IntentSender to send"); - return false; - } + public Bundle getIntentExtras() { + return mIntentExtras; } @Override public String toString() { return "ChooserTarget{" - + (mIntentSender != null ? mIntentSender.getCreatorPackage() : null) - + ", " - + "'" + mTitle + + mComponentName + + ", " + mIntentExtras + + ", '" + mTitle + "', " + mScore + "}"; } @@ -255,7 +198,8 @@ public final class ChooserTarget implements Parcelable { dest.writeInt(0); } dest.writeFloat(mScore); - IntentSender.writeIntentSenderOrNullToParcel(mIntentSender, dest); + ComponentName.writeToParcel(mComponentName, dest); + dest.writeBundle(mIntentExtras); } public static final Creator<ChooserTarget> CREATOR diff --git a/core/java/android/service/chooser/ChooserTargetService.java b/core/java/android/service/chooser/ChooserTargetService.java index a3bfece..e054185 100644 --- a/core/java/android/service/chooser/ChooserTargetService.java +++ b/core/java/android/service/chooser/ChooserTargetService.java @@ -105,9 +105,8 @@ public abstract class ChooserTargetService extends Service { * can handle an intent. * * <p>The returned list should be sorted such that the most relevant targets appear first. - * Any PendingIntents used to construct the resulting ChooserTargets should always be prepared - * to have the relevant data fields filled in by the sender. See - * {@link ChooserTarget#ChooserTarget(CharSequence, android.graphics.drawable.Icon, float, android.app.PendingIntent) ChooserTarget}.</p> + * The score for each ChooserTarget will be combined with the system's score for the original + * target Activity to sort and filter targets presented to the user.</p> * * <p><em>Important:</em> Calls to this method from other applications will occur on * a binder thread, not on your app's main thread. Make sure that access to relevant data diff --git a/core/java/android/service/chooser/IChooserTargetResult.aidl b/core/java/android/service/chooser/IChooserTargetResult.aidl index dbd7cbd..6c648a2 100644 --- a/core/java/android/service/chooser/IChooserTargetResult.aidl +++ b/core/java/android/service/chooser/IChooserTargetResult.aidl @@ -21,7 +21,7 @@ import android.service.chooser.ChooserTarget; /** * @hide */ -interface IChooserTargetResult +oneway interface IChooserTargetResult { void sendResult(in List<ChooserTarget> targets); } diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl index 8fe84e1..dbc28f7 100644 --- a/core/java/android/service/voice/IVoiceInteractionSession.aidl +++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl @@ -35,5 +35,6 @@ oneway interface IVoiceInteractionSession { void taskStarted(in Intent intent, int taskId); void taskFinished(in Intent intent, int taskId); void closeSystemDialogs(); + void onLockscreenShown(); void destroy(); } diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 95f96e8..f647aa6 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -91,6 +91,12 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall */ public static final int SHOW_SOURCE_ASSIST_GESTURE = 1<<2; + /** + * Flag for use with {@link #onShow}: indicates that the application itself has invoked + * the assistant. + */ + public static final int SHOW_SOURCE_APPLICATION = 1<<3; + final Context mContext; final HandlerCaller mHandlerCaller; @@ -259,6 +265,11 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } @Override + public void onLockscreenShown() { + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_ON_LOCKSCREEN_SHOWN)); + } + + @Override public void destroy() { mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DESTROY)); } @@ -316,6 +327,22 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall return mExtras; } + /** + * Check whether this request is currently active. A request becomes inactive after + * calling {@link #cancel} or a final result method that completes the request. After + * this point, further interactions with the request will result in + * {@link java.lang.IllegalStateException} errors; you should not catch these errors, + * but can use this method if you need to determine the state of the request. Returns + * true if the request is still active. + */ + public boolean isActive() { + VoiceInteractionSession session = mSession.get(); + if (session == null) { + return false; + } + return session.isRequestActive(mInterface.asBinder()); + } + void finishRequest() { VoiceInteractionSession session = mSession.get(); if (session == null) { @@ -332,6 +359,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall /** * Ask the app to cancel this current request. + * This also finishes the request (it is no longer active). */ public void cancel() { try { @@ -383,6 +411,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * in a call to * {@link android.app.VoiceInteractor.ConfirmationRequest#onConfirmationResult * VoiceInteractor.ConfirmationRequest.onConfirmationResult}. + * This finishes the request (it is no longer active). */ public void sendConfirmationResult(boolean confirmed, Bundle result) { try { @@ -469,6 +498,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * and resulting in a call to * {@link android.app.VoiceInteractor.PickOptionRequest#onPickOptionResult * VoiceInteractor.PickOptionRequest.onPickOptionResult} with false for finished. + * This finishes the request (it is no longer active). */ public void sendPickOptionResult( VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) { @@ -516,6 +546,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * in a call to * {@link android.app.VoiceInteractor.CompleteVoiceRequest#onCompleteResult * VoiceInteractor.CompleteVoiceRequest.onCompleteResult}. + * This finishes the request (it is no longer active). */ public void sendCompleteResult(Bundle result) { try { @@ -564,7 +595,8 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * Report that the voice interactor has finished aborting the voice operation, resulting * in a call to * {@link android.app.VoiceInteractor.AbortVoiceRequest#onAbortResult - * VoiceInteractor.AbortVoiceRequest.onAbortResult}. + * VoiceInteractor.AbortVoiceRequest.onAbortResult}. This finishes the request (it + * is no longer active). */ public void sendAbortResult(Bundle result) { try { @@ -624,6 +656,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * Report the final result of the request, completing the request and resulting in a call to * {@link android.app.VoiceInteractor.CommandRequest#onCommandResult * VoiceInteractor.CommandRequest.onCommandResult} with true for isCompleted. + * This finishes the request (it is no longer active). */ public void sendResult(Bundle result) { sendCommandResult(true, result); @@ -646,6 +679,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall static final int MSG_HANDLE_SCREENSHOT = 105; static final int MSG_SHOW = 106; static final int MSG_HIDE = 107; + static final int MSG_ON_LOCKSCREEN_SHOWN = 108; class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback { @Override @@ -724,6 +758,10 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall if (DEBUG) Log.d(TAG, "doHide"); doHide(); break; + case MSG_ON_LOCKSCREEN_SHOWN: + if (DEBUG) Log.d(TAG, "onLockscreenShown"); + onLockscreenShown(); + break; } if (args != null) { args.recycle(); @@ -814,7 +852,15 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } void addRequest(Request req) { - mActiveRequests.put(req.mInterface.asBinder(), req); + synchronized (this) { + mActiveRequests.put(req.mInterface.asBinder(), req); + } + } + + boolean isRequestActive(IBinder reqInterface) { + synchronized (this) { + return mActiveRequests.containsKey(reqInterface); + } } Request removeRequest(IBinder reqInterface) { @@ -936,6 +982,23 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } /** + * Return which show context flags have been disabled by the user through the system + * settings UI, so the session will never get this data. Returned flags are any combination of + * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and + * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT + * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}. Note that this only tells you about + * global user settings, not about restrictions that may be applied contextual based on + * the current application the user is in or other transient states. + */ + public int getUserDisabledShowContext() { + try { + return mSystemService.getUserDisabledShowContext(); + } catch (RemoteException e) { + return 0; + } + } + + /** * Show the UI for this session. This asks the system to go through the process of showing * your UI, which will eventually culminate in {@link #onShow}. This is similar to calling * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}. @@ -1179,23 +1242,33 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall /** * Called to receive data from the application that the user was currently viewing when - * an assist session is started. + * an assist session is started. If the original show request did not specify + * {@link #SHOW_WITH_ASSIST}, this method will not be called. * * @param data Arbitrary data supplied by the app through * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. + * May be null if assist data has been disabled by the user or device policy. * @param structure If available, the structure definition of all windows currently - * displayed by the app; if structure has been turned off by the user, will be null. + * displayed by the app. May be null if assist data has been disabled by the user + * or device policy; will be an empty stub if the application has disabled assist + * by marking its window as secure. * @param content Additional content data supplied by the app through * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}. + * May be null if assist data has been disabled by the user or device policy; will + * not be automatically filled in with data from the app if the app has marked its + * window as secure. */ - public void onHandleAssist(Bundle data, AssistStructure structure, AssistContent content) { + public void onHandleAssist(@Nullable Bundle data, @Nullable AssistStructure structure, + @Nullable AssistContent content) { } /** * Called to receive a screenshot of what the user was currently viewing when an assist - * session is started. Will be null if screenshots are disabled by the user. + * session is started. May be null if screenshots are disabled by the user, policy, + * or application. If the original show request did not specify + * {@link #SHOW_WITH_SCREENSHOT}, this method will not be called. */ - public void onHandleScreenshot(Bitmap screenshot) { + public void onHandleScreenshot(@Nullable Bitmap screenshot) { } public boolean onKeyDown(int keyCode, KeyEvent event) { @@ -1233,6 +1306,13 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall hide(); } + /** + * Called when the lockscreen was shown. + */ + public void onLockscreenShown() { + hide(); + } + @Override public void onConfigurationChanged(Configuration newConfig) { } diff --git a/core/java/android/text/BidiFormatter.java b/core/java/android/text/BidiFormatter.java index 7ea9da1..5c088cd 100644 --- a/core/java/android/text/BidiFormatter.java +++ b/core/java/android/text/BidiFormatter.java @@ -173,7 +173,7 @@ public final class BidiFormatter { /** * Specifies whether the BidiFormatter to be built should also "reset" directionality before - * a string being bidi-wrapped, not just after it. The default is false. + * a string being bidi-wrapped, not just after it. The default is true. */ public Builder stereoReset(boolean stereoReset) { if (stereoReset) { @@ -363,12 +363,13 @@ public final class BidiFormatter { * If {@code isolate}, directionally isolates the string so that it does not garble its * surroundings. Currently, this is done by "resetting" the directionality after the string by * appending a trailing Unicode bidi mark matching the context directionality (LRM or RLM) when - * either the overall directionality or the exit directionality of the string is opposite to that - * of the context. If the formatter was built using {@link Builder#stereoReset(boolean)} and - * passing "true" as an argument, also prepends a Unicode bidi mark matching the context - * directionality when either the overall directionality or the entry directionality of the - * string is opposite to that of the context. Note that as opposed to the overall - * directionality, the entry and exit directionalities are determined from the string itself. + * either the overall directionality or the exit directionality of the string is opposite to + * that of the context. Unless the formatter was built using + * {@link Builder#stereoReset(boolean)} with a {@code false} argument, also prepends a Unicode + * bidi mark matching the context directionality when either the overall directionality or the + * entry directionality of the string is opposite to that of the context. Note that as opposed + * to the overall directionality, the entry and exit directionalities are determined from the + * string itself. * <p> * Does *not* do HTML-escaping. * diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 605b91d..39e8694 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -741,11 +741,11 @@ class TextLine { if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) { if (mCharsValid) { - ret = wp.getRunAdvance(mChars, start, contextEnd, contextStart, contextEnd, + ret = wp.getRunAdvance(mChars, start, end, contextStart, contextEnd, runIsRtl, end); } else { int delta = mStart; - ret = wp.getRunAdvance(mText, delta + start, delta + contextEnd, + ret = wp.getRunAdvance(mText, delta + start, delta + end, delta + contextStart, delta + contextEnd, runIsRtl, delta + end); } } diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java index 82689b9..b5068b2 100644 --- a/core/java/android/text/format/Formatter.java +++ b/core/java/android/text/format/Formatter.java @@ -16,12 +16,18 @@ package android.text.format; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.Resources; +import android.text.BidiFormatter; +import android.text.TextUtils; +import android.view.View; import android.net.NetworkUtils; import android.net.TrafficStats; +import java.util.Locale; + /** * Utility class to aid in formatting common values that are not covered * by the {@link java.util.Formatter} class in {@link java.util} @@ -46,8 +52,23 @@ public final class Formatter { } } + /* Wraps the source string in bidi formatting characters in RTL locales */ + private static String bidiWrap(@NonNull Context context, String source) { + final Locale locale = context.getResources().getConfiguration().locale; + if (TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL) { + return BidiFormatter.getInstance(true /* RTL*/).unicodeWrap(source); + } else { + return source; + } + } + /** - * Formats a content size to be in the form of bytes, kilobytes, megabytes, etc + * Formats a content size to be in the form of bytes, kilobytes, megabytes, etc. + * + * If the context has a right-to-left locale, the returned string is wrapped in bidi formatting + * characters to make sure it's displayed correctly if inserted inside a right-to-left string. + * (This is useful in cases where the unit strings, like "MB", are left-to-right, but the + * locale is right-to-left.) * * @param context Context to use to load the localized units * @param sizeBytes size value to be formatted, in bytes @@ -58,8 +79,8 @@ public final class Formatter { return ""; } final BytesResult res = formatBytes(context.getResources(), sizeBytes, 0); - return context.getString(com.android.internal.R.string.fileSizeSuffix, - res.value, res.units); + return bidiWrap(context, context.getString(com.android.internal.R.string.fileSizeSuffix, + res.value, res.units)); } /** @@ -71,8 +92,8 @@ public final class Formatter { return ""; } final BytesResult res = formatBytes(context.getResources(), sizeBytes, FLAG_SHORTER); - return context.getString(com.android.internal.R.string.fileSizeSuffix, - res.value, res.units); + return bidiWrap(context, context.getString(com.android.internal.R.string.fileSizeSuffix, + res.value, res.units)); } /** {@hide} */ diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java index 39f66a5..a405dab 100644 --- a/core/java/android/util/LocalLog.java +++ b/core/java/android/util/LocalLog.java @@ -30,20 +30,32 @@ public final class LocalLog { private LinkedList<String> mLog; private int mMaxLines; private long mNow; + private final boolean mKeepFirst; public LocalLog(int maxLines) { mLog = new LinkedList<String>(); mMaxLines = maxLines; + mKeepFirst = false; + } + + public LocalLog(int maxLines, boolean keepFirst) { + mLog = new LinkedList<String>(); + mMaxLines = maxLines; + mKeepFirst = keepFirst; } public synchronized void log(String msg) { + mNow = System.currentTimeMillis(); + StringBuilder sb = new StringBuilder(); + Calendar c = Calendar.getInstance(); + c.setTimeInMillis(mNow); + sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); + logStraight(sb.toString() + " - " + msg); + } + + private synchronized void logStraight(String msg) { + if (mKeepFirst == false || mLog.size() < mMaxLines) mLog.add(msg); if (mMaxLines > 0) { - mNow = System.currentTimeMillis(); - StringBuilder sb = new StringBuilder(); - Calendar c = Calendar.getInstance(); - c.setTimeInMillis(mNow); - sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); - mLog.add(sb.toString() + " - " + msg); while (mLog.size() > mMaxLines) mLog.remove(); } } @@ -74,4 +86,13 @@ public final class LocalLog { public ReadOnlyLocalLog readOnlyLocalLog() { return new ReadOnlyLocalLog(this); } + + public synchronized void copyTo(LocalLog other, int lines) { + int end = mLog.size()-1; + int begin = end - lines; + if (begin < 0) begin = 0; + for (; begin < end; begin++) { + other.logStraight(mLog.get(begin)); + } + } } diff --git a/core/java/android/view/inputmethod/InputMethodManagerInternal.java b/core/java/android/view/inputmethod/InputMethodManagerInternal.java new file mode 100644 index 0000000..c22127b --- /dev/null +++ b/core/java/android/view/inputmethod/InputMethodManagerInternal.java @@ -0,0 +1,30 @@ +/* + * 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.view.inputmethod; + +/** + * Input method manager local system service interface. + * + * @hide Only for use within the system server. + */ +public interface InputMethodManagerInternal { + /** + * Called by the power manager to tell the input method manager whether it + * should start watching for wake events. + */ + public void setInteractive(boolean interactive); +} diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index b2b98db..ed858e7 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -1556,13 +1556,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (accessibilityId == getAccessibilityViewId()) { return this; } - // If the data changed the children are invalid since the data model changed. - // Hence, we pretend they do not exist. After a layout the children will sync - // with the model at which point we notify that the accessibility state changed, - // so a service will be able to re-fetch the views. - if (mDataChanged) { - return null; - } return super.findViewByAccessibilityIdTraversal(accessibilityId); } @@ -2409,18 +2402,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te class ListItemAccessibilityDelegate extends AccessibilityDelegate { @Override - public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { - // If the data changed the children are invalid since the data model changed. - // Hence, we pretend they do not exist. After a layout the children will sync - // with the model at which point we notify that the accessibility state changed, - // so a service will be able to re-fetch the views. - if (mDataChanged) { - return null; - } - return super.createAccessibilityNodeInfo(host); - } - - @Override public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(host, info); diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java index e3ce6f2..a12b15e 100644 --- a/core/java/android/widget/AppSecurityPermissions.java +++ b/core/java/android/widget/AppSecurityPermissions.java @@ -533,6 +533,12 @@ public class AppSecurityPermissions { int existingReqFlags) { final int base = pInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE; final boolean isNormal = (base == PermissionInfo.PROTECTION_NORMAL); + + // We do not show normal permissions in the UI. + if (isNormal) { + return false; + } + final boolean isDangerous = (base == PermissionInfo.PROTECTION_DANGEROUS) || ((pInfo.protectionLevel&PermissionInfo.PROTECTION_FLAG_PRE23) != 0); final boolean isRequired = @@ -546,7 +552,7 @@ public class AppSecurityPermissions { // Dangerous and normal permissions are always shown to the user if the permission // is required, or it was previously granted - if ((isNormal || isDangerous) && (isRequired || wasGranted || isGranted)) { + if (isDangerous && (isRequired || wasGranted || isGranted)) { return true; } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index d897f49..e169ceb 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -1004,7 +1004,8 @@ public class Editor { } if (!handled && mTextActionMode != null) { - if (touchPositionIsInSelection()) { + // TODO: Fix dragging in extracted mode. + if (touchPositionIsInSelection() && !mTextView.isInExtractedMode()) { // Start a drag final int start = mTextView.getSelectionStart(); final int end = mTextView.getSelectionEnd(); @@ -3225,7 +3226,8 @@ public class Editor { } private void updateReplaceItem(Menu menu) { - boolean canReplace = mTextView.isSuggestionsEnabled() && shouldOfferToShowSuggestions(); + boolean canReplace = mTextView.isSuggestionsEnabled() && shouldOfferToShowSuggestions() + && !(mTextView.isInExtractedMode() && mTextView.hasSelection()); boolean replaceItemExists = menu.findItem(TextView.ID_REPLACE) != null; if (canReplace && !replaceItemExists) { menu.add(Menu.NONE, TextView.ID_REPLACE, MENU_ITEM_ORDER_REPLACE, diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index dac02fa..6a561e6 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -731,7 +731,8 @@ public class RelativeLayout extends ViewGroup { // Negative values in a mySize value in RelativeLayout // measurement is code for, "we got an unspecified mode in the // RelativeLayout's measure spec." - if (mySize < 0 && !mAllowBrokenMeasureSpecs) { + final boolean isUnspecified = mySize < 0; + if (isUnspecified && !mAllowBrokenMeasureSpecs) { if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) { // Constraints fixed both edges, so child has an exact size. childSpecSize = Math.max(0, childEnd - childStart); @@ -767,7 +768,7 @@ public class RelativeLayout extends ViewGroup { if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) { // Constraints fixed both edges, so child must be an exact size. - childSpecMode = MeasureSpec.EXACTLY; + childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY; childSpecSize = Math.max(0, maxAvailable); } else { if (childSize >= 0) { @@ -784,7 +785,7 @@ public class RelativeLayout extends ViewGroup { } else if (childSize == LayoutParams.MATCH_PARENT) { // Child wanted to be as big as possible. Give all available // space. - childSpecMode = MeasureSpec.EXACTLY; + childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY; childSpecSize = Math.max(0, maxAvailable); } else if (childSize == LayoutParams.WRAP_CONTENT) { // Child wants to wrap content. Use AT_MOST to communicate diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java index acf1df9..6e04eac 100644 --- a/core/java/android/widget/SimpleMonthView.java +++ b/core/java/android/widget/SimpleMonthView.java @@ -42,6 +42,7 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import com.android.internal.R; import com.android.internal.widget.ExploreByTouchHelper; +import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Locale; @@ -73,6 +74,7 @@ class SimpleMonthView extends View { private final SimpleDateFormat mTitleFormatter; private final SimpleDateFormat mDayOfWeekFormatter; + private final NumberFormat mDayFormatter; // Desired dimensions. private final int mDesiredMonthHeight; @@ -162,6 +164,7 @@ class SimpleMonthView extends View { final String titleFormat = DateFormat.getBestDateTimePattern(locale, DEFAULT_TITLE_FORMAT); mTitleFormatter = new SimpleDateFormat(titleFormat, locale); mDayOfWeekFormatter = new SimpleDateFormat(DAY_OF_WEEK_FORMAT, locale); + mDayFormatter = NumberFormat.getIntegerInstance(locale); initPaints(res); } @@ -454,7 +457,7 @@ class SimpleMonthView extends View { } p.setColor(dayTextColor); - canvas.drawText(Integer.toString(day), colCenterRtl, rowCenter - halfLineHeight, p); + canvas.drawText(mDayFormatter.format(day), colCenterRtl, rowCenter - halfLineHeight, p); col++; @@ -866,7 +869,7 @@ class SimpleMonthView extends View { */ private CharSequence getDayText(int id) { if (isValidDayOfMonth(id)) { - return Integer.toString(id); + return mDayFormatter.format(id); } return null; |
