diff options
Diffstat (limited to 'core/java')
104 files changed, 2146 insertions, 668 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 49f5099..90567c7 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -38,6 +38,7 @@ import com.android.internal.app.ToolbarActionBar; import android.annotation.SystemApi; import android.app.admin.DevicePolicyManager; +import android.app.assist.AssistContent; import android.content.ComponentCallbacks2; import android.content.ComponentName; import android.content.ContentResolver; @@ -3746,6 +3747,7 @@ public class Activity extends ContextThemeWrapper * * @see #onRequestPermissionsResult(int, String[], int[]) * @see #checkSelfPermission(String) + * @see #shouldShowRequestPermissionRationale(String) */ public final void requestPermissions(@NonNull String[] permissions, int requestCode) { Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions); @@ -3770,6 +3772,30 @@ public class Activity extends ContextThemeWrapper } /** + * Gets whether you should show UI with rationale for requesting a permission. + * You should do this only if you do not have the permission and the context in + * which the permission is requested does not clearly communicate to the user + * what would be the benefit from granting this permission. + * <p> + * For example, if you write a camera app, requesting the camera permission + * would be expected by the user and no rationale for why it is requested is + * needed. If however, the app needs location for tagging photos then a non-tech + * savvy user may wonder how location is related to taking photos. In this case + * you may choose to show UI with rationale of requesting this permission. + * </p> + * + * @param permission A permission your app wants to request. + * @return Whether you can show permission rationale UI. + * + * @see #checkSelfPermission(String) + * @see #requestPermissions(String[], int) + * @see #onRequestPermissionsResult(int, String[], int[]) + */ + public boolean shouldShowRequestPermissionRationale(@NonNull String permission) { + return getPackageManager().shouldShowRequestPermissionRationale(permission); + } + + /** * Same as calling {@link #startActivityForResult(Intent, int, Bundle)} * with no options. * diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index e4def1e..b6cec60 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -17,6 +17,8 @@ package android.app; import android.app.ActivityManager.StackInfo; +import android.app.assist.AssistContent; +import android.app.assist.AssistStructure; import android.content.ComponentName; import android.content.IIntentReceiver; import android.content.IIntentSender; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 2a98b6c..3224d41 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -16,6 +16,8 @@ package android.app; +import android.app.assist.AssistContent; +import android.app.assist.AssistStructure; import android.app.backup.BackupAgent; import android.content.BroadcastReceiver; import android.content.ComponentCallbacks2; diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 04f6430..41e3db8 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -486,6 +486,16 @@ final class ApplicationPackageManager extends PackageManager { } @Override + public boolean shouldShowRequestPermissionRationale(String permission) { + try { + return mPM.shouldShowRequestPermissionRationale(permission, + mContext.getPackageName(), mContext.getUserId()); + } catch (RemoteException e) { + throw new RuntimeException("Package manager has died", e); + } + } + + @Override public int checkSignatures(String pkg1, String pkg2) { try { return mPM.checkSignatures(pkg1, pkg2); diff --git a/core/java/android/app/AssistContent.java b/core/java/android/app/AssistContent.java index f271af1..4cb89a8 100644 --- a/core/java/android/app/AssistContent.java +++ b/core/java/android/app/AssistContent.java @@ -26,9 +26,11 @@ import android.os.Parcelable; /** * Holds information about the content an application is viewing, to hand to an * assistant at the user's request. This is filled in by - * {@link Activity#onProvideAssistContent Activity.onProvideAssistContent}. + * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}. + * @deprecated use {@link android.app.assist.AssistContent}. */ -public class AssistContent implements Parcelable { +@Deprecated +public class AssistContent { private Intent mIntent; private ClipData mClipData; private Uri mUri; @@ -36,16 +38,16 @@ public class AssistContent implements Parcelable { /** * @hide * Key name this data structure is stored in the Bundle generated by - * {@link Activity#onProvideAssistData}. + * {@link android.app.Activity#onProvideAssistData}. */ public static final String ASSIST_KEY = "android:assist_content"; /** * @hide * Retrieve the framework-generated AssistContent that is stored within - * the Bundle filled in by {@link Activity#onProvideAssistContent}. + * the Bundle filled in by {@link android.app.Activity#onProvideAssistContent}. */ - public static AssistContent getAssistContent(Bundle assistBundle) { + public static android.app.assist.AssistContent getAssistContent(Bundle assistBundle) { return assistBundle.getParcelable(ASSIST_KEY); } @@ -71,6 +73,7 @@ public class AssistContent implements Parcelable { /** * Return the current {@link #setIntent}, which you can modify in-place. + * @hide */ public Intent getIntent() { return mIntent; @@ -116,7 +119,8 @@ public class AssistContent implements Parcelable { return mUri; } - AssistContent(Parcel in) { + /** @hide */ + public AssistContent(Parcel in) { if (in.readInt() != 0) { mIntent = Intent.CREATOR.createFromParcel(in); } @@ -128,13 +132,8 @@ public class AssistContent implements Parcelable { } } - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { if (mIntent != null) { dest.writeInt(1); mIntent.writeToParcel(dest, flags); @@ -154,15 +153,4 @@ public class AssistContent implements Parcelable { dest.writeInt(0); } } - - public static final Parcelable.Creator<AssistContent> CREATOR - = new Parcelable.Creator<AssistContent>() { - public AssistContent createFromParcel(Parcel in) { - return new AssistContent(in); - } - - public AssistContent[] newArray(int size) { - return new AssistContent[size]; - } - }; } diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java index ca47a5e..ef7fde4 100644 --- a/core/java/android/app/AssistStructure.java +++ b/core/java/android/app/AssistStructure.java @@ -17,9 +17,7 @@ package android.app; import android.content.ComponentName; -import android.graphics.Paint; import android.graphics.Rect; -import android.graphics.Typeface; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -29,7 +27,6 @@ import android.os.PooledStringReader; import android.os.PooledStringWriter; import android.os.RemoteException; import android.os.SystemClock; -import android.text.TextPaint; import android.text.TextUtils; import android.util.Log; import android.view.View; @@ -42,19 +39,22 @@ import java.util.ArrayList; /** * Assist data automatically created by the platform's implementation - * of {@link Activity#onProvideAssistData}. + * of {@link android.app.Activity#onProvideAssistData}. + * @deprecated use {@link android.app.assist.AssistStructure}. */ -final public class AssistStructure implements Parcelable { +@Deprecated +public class AssistStructure { static final String TAG = "AssistStructure"; /** * @hide * Key name this data structure is stored in the Bundle generated by - * {@link Activity#onProvideAssistData}. + * {@link android.app.Activity#onProvideAssistData}. */ public static final String ASSIST_KEY = "android:assist_structure"; - boolean mHaveData; + /** @hide */ + public boolean mHaveData; ComponentName mActivityComponent; @@ -62,15 +62,18 @@ final public class AssistStructure implements Parcelable { final ArrayList<ViewNodeBuilder> mPendingAsyncChildren = new ArrayList<>(); - SendChannel mSendChannel; - IBinder mReceiveChannel; + /** @hide */ + public SendChannel mSendChannel; + /** @hide */ + public IBinder mReceiveChannel; Rect mTmpRect = new Rect(); static final int TRANSACTION_XFER = Binder.FIRST_CALL_TRANSACTION+1; static final String DESCRIPTOR = "android.app.AssistStructure"; - final class SendChannel extends Binder { + /** @hide */ + public final class SendChannel extends Binder { @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { if (code == TRANSACTION_XFER) { @@ -702,7 +705,8 @@ final public class AssistStructure implements Parcelable { } } - AssistStructure(Activity activity) { + /** @hide */ + public AssistStructure(Activity activity) { mHaveData = true; mActivityComponent = activity.getComponentName(); ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews( @@ -713,12 +717,13 @@ final public class AssistStructure implements Parcelable { } } - AssistStructure() { + public AssistStructure() { mHaveData = true; mActivityComponent = null; } - AssistStructure(Parcel in) { + /** @hide */ + public AssistStructure(Parcel in) { mReceiveChannel = in.readStrongBinder(); } @@ -792,7 +797,7 @@ final public class AssistStructure implements Parcelable { * Retrieve the framework-generated AssistStructure that is stored within * the Bundle filled in by {@link Activity#onProvideAssistData}. */ - public static AssistStructure getAssistStructure(Bundle assistBundle) { + public static android.app.assist.AssistStructure getAssistStructure(Bundle assistBundle) { return assistBundle.getParcelable(ASSIST_KEY); } @@ -812,16 +817,13 @@ final public class AssistStructure implements Parcelable { /** * Return one of the windows in the assist data. * @param index Which window to retrieve, may be 0 to {@link #getWindowNodeCount()}-1. + * @hide */ public WindowNode getWindowNodeAt(int index) { ensureData(); return mWindowNodes.get(index); } - public int describeContents() { - return 0; - } - /** @hide */ public void ensureData() { if (mHaveData) { @@ -880,29 +882,4 @@ final public class AssistStructure implements Parcelable { } //dump(); } - - public void writeToParcel(Parcel out, int flags) { - if (mHaveData) { - // This object holds its data. We want to write a send channel that the - // other side can use to retrieve that data. - if (mSendChannel == null) { - mSendChannel = new SendChannel(); - } - out.writeStrongBinder(mSendChannel); - } else { - // This object doesn't hold its data, so just propagate along its receive channel. - out.writeStrongBinder(mReceiveChannel); - } - } - - public static final Parcelable.Creator<AssistStructure> CREATOR - = new Parcelable.Creator<AssistStructure>() { - public AssistStructure createFromParcel(Parcel in) { - return new AssistStructure(in); - } - - public AssistStructure[] newArray(int size) { - return new AssistStructure[size]; - } - }; } diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java index 1fb88a9..02e26a5 100644 --- a/core/java/android/app/BackStackRecord.java +++ b/core/java/android/app/BackStackRecord.java @@ -1107,6 +1107,7 @@ final class BackStackRecord extends FragmentTransaction implements } if (enterTransition != null) { + enterTransition.removeTarget(state.nonExistentView); View view = inFragment.getView(); if (view != null) { view.captureTransitioningViews(enteringViews); @@ -1115,7 +1116,6 @@ final class BackStackRecord extends FragmentTransaction implements } enteringViews.add(state.nonExistentView); // We added this earlier to prevent any views being targeted. - enterTransition.removeTarget(state.nonExistentView); addTargets(enterTransition, enteringViews); } setSharedElementEpicenter(enterTransition, state); @@ -1170,7 +1170,7 @@ final class BackStackRecord extends FragmentTransaction implements Transition exitTransition, Transition sharedElementTransition, Fragment inFragment, boolean isBack) { boolean overlap = true; - if (enterTransition != null && exitTransition != null) { + if (enterTransition != null && exitTransition != null && inFragment != null) { overlap = isBack ? inFragment.getAllowReturnTransitionOverlap() : inFragment.getAllowEnterTransitionOverlap(); } @@ -1638,7 +1638,7 @@ final class BackStackRecord extends FragmentTransaction implements private void setBackNameOverrides(TransitionState state, ArrayMap<String, View> namedViews, boolean isEnd) { - int count = mSharedElementTargetNames.size(); + int count = mSharedElementTargetNames == null ? 0 : mSharedElementTargetNames.size(); for (int i = 0; i < count; i++) { String source = mSharedElementSourceNames.get(i); String originalTarget = mSharedElementTargetNames.get(i); @@ -1656,7 +1656,7 @@ final class BackStackRecord extends FragmentTransaction implements private void setNameOverrides(TransitionState state, ArrayMap<String, View> namedViews, boolean isEnd) { - int count = namedViews.size(); + int count = namedViews == null ? 0 : namedViews.size(); for (int i = 0; i < count; i++) { String source = namedViews.keyAt(i); String target = namedViews.valueAt(i).getTransitionName(); diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 40c5c64..26d4fd4 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -1223,6 +1223,33 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } /** + * Gets whether you should show UI with rationale for requesting a permission. + * You should do this only if you do not have the permission and the context in + * which the permission is requested does not clearly communicate to the user + * what would be the benefit from granting this permission. + * <p> + * For example, if you write a camera app, requesting the camera permission + * would be expected by the user and no rationale for why it is requested is + * needed. If however, the app needs location for tagging photos then a non-tech + * savvy user may wonder how location is related to taking photos. In this case + * you may choose to show UI with rationale of requesting this permission. + * </p> + * + * @param permission A permission your app wants to request. + * @return Whether you can show permission rationale UI. + * + * @see Context#checkSelfPermission(String) + * @see #requestPermissions(String[], int) + * @see #onRequestPermissionsResult(int, String[], int[]) + */ + public boolean shouldShowRequestPermissionRationale(@NonNull String permission) { + if (mHost != null) { + mHost.getContext().getPackageManager().shouldShowRequestPermissionRationale(permission); + } + return false; + } + + /** * @hide Hack so that DialogFragment can make its Dialog before creating * its views, and the view construction can use the dialog's context for * inflation. Maybe this should become a public API. Note sure. diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 0a425ae..249cdb2 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -19,6 +19,8 @@ package android.app; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.RunningServiceInfo; import android.app.ActivityManager.StackInfo; +import android.app.assist.AssistContent; +import android.app.assist.AssistStructure; import android.content.ComponentName; import android.content.ContentProviderNative; import android.content.IContentProvider; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 978b4bc..55eaf27 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -16,6 +16,8 @@ package android.app.admin; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; @@ -76,7 +78,7 @@ import java.util.List; * <h3>Developer Guides</h3> * <p>For more information about managing policies for device administration, read the * <a href="{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a> - * developer guide.</p> + * developer guide. * </div> */ public class DevicePolicyManager { @@ -122,15 +124,45 @@ public class DevicePolicyManager { * * <p> If provisioning fails, the managedProfile is removed so the device returns to its * previous state. - * - * <p>Input: Nothing.</p> - * <p>Output: Nothing</p> */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE"; /** + * Activity action: Starts the provisioning flow which sets up a managed device. + * Must be started with {@link android.app.Activity#startActivityForResult(Intent, int)}. + * + * <p> During device owner provisioning a device admin app is set as the owner of the device. + * A device owner has full control over the device. The device owner can not be modified by the + * user. + * + * <p> A typical use case would be a device that is owned by a company, but used by either an + * employee or client. + * + * <p> An intent with this action can be sent only on an unprovisioned device. + * It is possible to check if the device is provisioned or not by looking at + * {@link android.provider.Settings.Global#DEVICE_PROVISIONED} + * + * The intent contains the following extras: + * <ul> + * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}</li> + * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li> + * <li>{@link #EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED}, optional</li> + * </ul> + * + * <p> When device owner provisioning has completed, an intent of the type + * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcast to the + * device owner. + * + * <p> If provisioning fails, the device is factory reset. + * + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_PROVISION_MANAGED_DEVICE + = "android.app.action.PROVISION_MANAGED_DEVICE"; + + /** * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that allows * a mobile device management application that starts managed profile provisioning to pass data * to itself on the managed profile when provisioning completes. The mobile device management @@ -155,7 +187,7 @@ public class DevicePolicyManager { * message containing an NFC record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}. * * <p> When this extra is set, the application must have exactly one device admin receiver. - * This receiver will be set as the profile or device owner and active admin.</p> + * This receiver will be set as the profile or device owner and active admin. * @see DeviceAdminReceiver * @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}. This extra is still @@ -170,11 +202,13 @@ public class DevicePolicyManager { * application that will be set as the profile owner or device owner and active admin. * * <p>If an application starts provisioning directly via an intent with action - * {@link #ACTION_PROVISION_MANAGED_PROFILE} the package name of this component has to match the - * package name of the application that started provisioning. + * {@link #ACTION_PROVISION_MANAGED_PROFILE} or + * {@link #ACTION_PROVISION_MANAGED_DEVICE} the package name of this + * component has to match the package name of the application that started provisioning. * * <p>This component is set as device owner and active admin when device owner provisioning is - * started by an NFC message containing an NFC record with MIME type + * started by an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE} or by an NFC + * message containing an NFC record with MIME type * {@link #MIME_TYPE_PROVISIONING_NFC_V2}. For the NFC record, the component name should be * flattened to a string, via {@link ComponentName#flattenToShortString()}. * @@ -212,10 +246,10 @@ public class DevicePolicyManager { /** * A Boolean extra that can be used by the mobile device management application to skip the - * disabling of system apps during provisioning when set to <code>true</code>. + * disabling of system apps during provisioning when set to {@code true}. * - * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner - * provisioning via an NFC bump. + * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} or an intent with action + * {@link #ACTION_PROVISION_MANAGED_DEVICE} that starts device owner provisioning. */ public static final String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED"; @@ -415,8 +449,8 @@ public class DevicePolicyManager { * A boolean extra indicating whether device encryption can be skipped as part of Device Owner * provisioning. * - * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner - * provisioning via an NFC bump. + * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} or an intent with action + * {@link #ACTION_PROVISION_MANAGED_DEVICE} that starts device owner provisioning. */ public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION"; @@ -610,8 +644,7 @@ public class DevicePolicyManager { * * <p>During device owner provisioning a device admin app is set as the owner of the device. * A device owner has full control over the device. The device owner can not be modified by the - * user and the only way of resetting the device is if the device owner app calls a factory - * reset. + * user. * * <p> A typical use case would be a device that is owned by a company, but used by either an * employee or client. @@ -644,9 +677,6 @@ public class DevicePolicyManager { * * <p> * If provisioning fails, the device is factory reset. - * - * <p>Input: Nothing.</p> - * <p>Output: Nothing</p> */ public static final String MIME_TYPE_PROVISIONING_NFC_V2 = "application/com.android.managedprovisioning.v2"; @@ -847,18 +877,18 @@ public class DevicePolicyManager { * Return true if the given administrator component is currently * active (enabled) in the system. */ - public boolean isAdminActive(ComponentName who) { - return isAdminActiveAsUser(who, UserHandle.myUserId()); + public boolean isAdminActive(@NonNull ComponentName admin) { + return isAdminActiveAsUser(admin, UserHandle.myUserId()); } /** * @see #isAdminActive(ComponentName) * @hide */ - public boolean isAdminActiveAsUser(ComponentName who, int userId) { + public boolean isAdminActiveAsUser(@NonNull ComponentName admin, int userId) { if (mService != null) { try { - return mService.isAdminActive(who, userId); + return mService.isAdminActive(admin, userId); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -870,10 +900,10 @@ public class DevicePolicyManager { * for the user. * @hide */ - public boolean isRemovingAdmin(ComponentName who, int userId) { + public boolean isRemovingAdmin(@NonNull ComponentName admin, int userId) { if (mService != null) { try { - return mService.isRemovingAdmin(who, userId); + return mService.isRemovingAdmin(admin, userId); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -883,8 +913,8 @@ public class DevicePolicyManager { /** - * Return a list of all currently active device administrator's component - * names. Note that if there are no administrators than null may be + * Return a list of all currently active device administrators' component + * names. If there are no administrators {@code null} may be * returned. */ public List<ComponentName> getActiveAdmins() { @@ -928,10 +958,10 @@ public class DevicePolicyManager { * try to remove someone else's component, a security exception will be * thrown. */ - public void removeActiveAdmin(ComponentName who) { + public void removeActiveAdmin(@NonNull ComponentName admin) { if (mService != null) { try { - mService.removeActiveAdmin(who, UserHandle.myUserId()); + mService.removeActiveAdmin(admin, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -940,14 +970,14 @@ public class DevicePolicyManager { /** * Returns true if an administrator has been granted a particular device policy. This can - * be used to check if the administrator was activated under an earlier set of policies, + * be used to check whether the administrator was activated under an earlier set of policies, * but requires additional policies after an upgrade. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Must be * an active administrator, or an exception will be thrown. * @param usesPolicy Which uses-policy to check, as defined in {@link DeviceAdminInfo}. */ - public boolean hasGrantedPolicy(ComponentName admin, int usesPolicy) { + public boolean hasGrantedPolicy(@NonNull ComponentName admin, int usesPolicy) { if (mService != null) { try { return mService.hasGrantedPolicy(admin, usesPolicy, UserHandle.myUserId()); @@ -1048,7 +1078,7 @@ public class DevicePolicyManager { * {@link #PASSWORD_QUALITY_ALPHABETIC}, {@link #PASSWORD_QUALITY_ALPHANUMERIC} * or {@link #PASSWORD_QUALITY_COMPLEX}. */ - public void setPasswordQuality(ComponentName admin, int quality) { + public void setPasswordQuality(@NonNull ComponentName admin, int quality) { if (mService != null) { try { mService.setPasswordQuality(admin, quality); @@ -1061,15 +1091,15 @@ public class DevicePolicyManager { /** * Retrieve the current minimum password quality for all admins of this user * and its profiles or a particular one. - * @param admin The name of the admin component to check, or null to aggregate + * @param admin The name of the admin component to check, or {@code null} to aggregate * all admins. */ - public int getPasswordQuality(ComponentName admin) { + public int getPasswordQuality(@Nullable ComponentName admin) { return getPasswordQuality(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordQuality(ComponentName admin, int userHandle) { + public int getPasswordQuality(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordQuality(admin, userHandle); @@ -1101,7 +1131,7 @@ public class DevicePolicyManager { * @param length The new desired minimum password length. A value of 0 * means there is no restriction. */ - public void setPasswordMinimumLength(ComponentName admin, int length) { + public void setPasswordMinimumLength(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordMinimumLength(admin, length); @@ -1114,15 +1144,15 @@ public class DevicePolicyManager { /** * Retrieve the current minimum password length for all admins of this * user and its profiles or a particular one. - * @param admin The name of the admin component to check, or null to aggregate + * @param admin The name of the admin component to check, or {@code null} to aggregate * all admins. */ - public int getPasswordMinimumLength(ComponentName admin) { + public int getPasswordMinimumLength(@Nullable ComponentName admin) { return getPasswordMinimumLength(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordMinimumLength(ComponentName admin, int userHandle) { + public int getPasswordMinimumLength(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordMinimumLength(admin, userHandle); @@ -1155,7 +1185,7 @@ public class DevicePolicyManager { * required in the password. A value of 0 means there is no * restriction. */ - public void setPasswordMinimumUpperCase(ComponentName admin, int length) { + public void setPasswordMinimumUpperCase(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordMinimumUpperCase(admin, length); @@ -1173,17 +1203,17 @@ public class DevicePolicyManager { * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * - * @param admin The name of the admin component to check, or null to + * @param admin The name of the admin component to check, or {@code null} to * aggregate all admins. * @return The minimum number of upper case letters required in the * password. */ - public int getPasswordMinimumUpperCase(ComponentName admin) { + public int getPasswordMinimumUpperCase(@Nullable ComponentName admin) { return getPasswordMinimumUpperCase(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordMinimumUpperCase(ComponentName admin, int userHandle) { + public int getPasswordMinimumUpperCase(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordMinimumUpperCase(admin, userHandle); @@ -1216,7 +1246,7 @@ public class DevicePolicyManager { * required in the password. A value of 0 means there is no * restriction. */ - public void setPasswordMinimumLowerCase(ComponentName admin, int length) { + public void setPasswordMinimumLowerCase(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordMinimumLowerCase(admin, length); @@ -1234,17 +1264,17 @@ public class DevicePolicyManager { * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * - * @param admin The name of the admin component to check, or null to + * @param admin The name of the admin component to check, or {@code null} to * aggregate all admins. * @return The minimum number of lower case letters required in the * password. */ - public int getPasswordMinimumLowerCase(ComponentName admin) { + public int getPasswordMinimumLowerCase(@Nullable ComponentName admin) { return getPasswordMinimumLowerCase(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordMinimumLowerCase(ComponentName admin, int userHandle) { + public int getPasswordMinimumLowerCase(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordMinimumLowerCase(admin, userHandle); @@ -1276,7 +1306,7 @@ public class DevicePolicyManager { * @param length The new desired minimum number of letters required in the * password. A value of 0 means there is no restriction. */ - public void setPasswordMinimumLetters(ComponentName admin, int length) { + public void setPasswordMinimumLetters(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordMinimumLetters(admin, length); @@ -1293,16 +1323,16 @@ public class DevicePolicyManager { * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * - * @param admin The name of the admin component to check, or null to + * @param admin The name of the admin component to check, or {@code null} to * aggregate all admins. * @return The minimum number of letters required in the password. */ - public int getPasswordMinimumLetters(ComponentName admin) { + public int getPasswordMinimumLetters(@Nullable ComponentName admin) { return getPasswordMinimumLetters(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordMinimumLetters(ComponentName admin, int userHandle) { + public int getPasswordMinimumLetters(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordMinimumLetters(admin, userHandle); @@ -1334,7 +1364,7 @@ public class DevicePolicyManager { * @param length The new desired minimum number of numerical digits required * in the password. A value of 0 means there is no restriction. */ - public void setPasswordMinimumNumeric(ComponentName admin, int length) { + public void setPasswordMinimumNumeric(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordMinimumNumeric(admin, length); @@ -1352,16 +1382,16 @@ public class DevicePolicyManager { * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * - * @param admin The name of the admin component to check, or null to + * @param admin The name of the admin component to check, or {@code null} to * aggregate all admins. * @return The minimum number of numerical digits required in the password. */ - public int getPasswordMinimumNumeric(ComponentName admin) { + public int getPasswordMinimumNumeric(@Nullable ComponentName admin) { return getPasswordMinimumNumeric(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordMinimumNumeric(ComponentName admin, int userHandle) { + public int getPasswordMinimumNumeric(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordMinimumNumeric(admin, userHandle); @@ -1393,7 +1423,7 @@ public class DevicePolicyManager { * @param length The new desired minimum number of symbols required in the * password. A value of 0 means there is no restriction. */ - public void setPasswordMinimumSymbols(ComponentName admin, int length) { + public void setPasswordMinimumSymbols(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordMinimumSymbols(admin, length); @@ -1410,16 +1440,16 @@ public class DevicePolicyManager { * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * - * @param admin The name of the admin component to check, or null to + * @param admin The name of the admin component to check, or {@code null} to * aggregate all admins. * @return The minimum number of symbols required in the password. */ - public int getPasswordMinimumSymbols(ComponentName admin) { + public int getPasswordMinimumSymbols(@Nullable ComponentName admin) { return getPasswordMinimumSymbols(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordMinimumSymbols(ComponentName admin, int userHandle) { + public int getPasswordMinimumSymbols(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordMinimumSymbols(admin, userHandle); @@ -1451,7 +1481,7 @@ public class DevicePolicyManager { * @param length The new desired minimum number of letters required in the * password. A value of 0 means there is no restriction. */ - public void setPasswordMinimumNonLetter(ComponentName admin, int length) { + public void setPasswordMinimumNonLetter(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordMinimumNonLetter(admin, length); @@ -1469,16 +1499,16 @@ public class DevicePolicyManager { * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * - * @param admin The name of the admin component to check, or null to + * @param admin The name of the admin component to check, or {@code null} to * aggregate all admins. * @return The minimum number of letters required in the password. */ - public int getPasswordMinimumNonLetter(ComponentName admin) { + public int getPasswordMinimumNonLetter(@Nullable ComponentName admin) { return getPasswordMinimumNonLetter(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordMinimumNonLetter(ComponentName admin, int userHandle) { + public int getPasswordMinimumNonLetter(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordMinimumNonLetter(admin, userHandle); @@ -1511,7 +1541,7 @@ public class DevicePolicyManager { * @param length The new desired length of password history. A value of 0 * means there is no restriction. */ - public void setPasswordHistoryLength(ComponentName admin, int length) { + public void setPasswordHistoryLength(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordHistoryLength(admin, length); @@ -1543,7 +1573,7 @@ public class DevicePolicyManager { * @param timeout The limit (in ms) that a password can remain in effect. A value of 0 * means there is no restriction (unlimited). */ - public void setPasswordExpirationTimeout(ComponentName admin, long timeout) { + public void setPasswordExpirationTimeout(@NonNull ComponentName admin, long timeout) { if (mService != null) { try { mService.setPasswordExpirationTimeout(admin, timeout); @@ -1557,12 +1587,12 @@ public class DevicePolicyManager { * Get the password expiration timeout for the given admin. The expiration timeout is the * recurring expiration timeout provided in the call to * {@link #setPasswordExpirationTimeout(ComponentName, long)} for the given admin or the - * aggregate of all policy administrators if admin is null. + * aggregate of all policy administrators if {@code admin} is null. * - * @param admin The name of the admin component to check, or null to aggregate all admins. + * @param admin The name of the admin component to check, or {@code null} to aggregate all admins. * @return The timeout for the given admin or the minimum of all timeouts */ - public long getPasswordExpirationTimeout(ComponentName admin) { + public long getPasswordExpirationTimeout(@Nullable ComponentName admin) { if (mService != null) { try { return mService.getPasswordExpirationTimeout(admin, UserHandle.myUserId()); @@ -1580,10 +1610,10 @@ public class DevicePolicyManager { * If admin is null, then a composite of all expiration timeouts is returned * - which will be the minimum of all timeouts. * - * @param admin The name of the admin component to check, or null to aggregate all admins. + * @param admin The name of the admin component to check, or {@code null} to aggregate all admins. * @return The password expiration time, in ms. */ - public long getPasswordExpiration(ComponentName admin) { + public long getPasswordExpiration(@Nullable ComponentName admin) { if (mService != null) { try { return mService.getPasswordExpiration(admin, UserHandle.myUserId()); @@ -1597,16 +1627,16 @@ public class DevicePolicyManager { /** * Retrieve the current password history length for all admins of this * user and its profiles or a particular one. - * @param admin The name of the admin component to check, or null to aggregate + * @param admin The name of the admin component to check, or {@code null} to aggregate * all admins. * @return The length of the password history */ - public int getPasswordHistoryLength(ComponentName admin) { + public int getPasswordHistoryLength(@Nullable ComponentName admin) { return getPasswordHistoryLength(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordHistoryLength(ComponentName admin, int userHandle) { + public int getPasswordHistoryLength(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordHistoryLength(admin, userHandle); @@ -1705,7 +1735,7 @@ public class DevicePolicyManager { * @param num The number of failed password attempts at which point the * device will wipe its data. */ - public void setMaximumFailedPasswordsForWipe(ComponentName admin, int num) { + public void setMaximumFailedPasswordsForWipe(@NonNull ComponentName admin, int num) { if (mService != null) { try { mService.setMaximumFailedPasswordsForWipe(admin, num); @@ -1719,15 +1749,15 @@ public class DevicePolicyManager { * Retrieve the current maximum number of login attempts that are allowed * before the device wipes itself, for all admins of this user and its profiles * or a particular one. - * @param admin The name of the admin component to check, or null to aggregate + * @param admin The name of the admin component to check, or {@code null} to aggregate * all admins. */ - public int getMaximumFailedPasswordsForWipe(ComponentName admin) { + public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin) { return getMaximumFailedPasswordsForWipe(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getMaximumFailedPasswordsForWipe(ComponentName admin, int userHandle) { + public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getMaximumFailedPasswordsForWipe(admin, userHandle); @@ -1824,7 +1854,7 @@ public class DevicePolicyManager { * @param timeMs The new desired maximum time to lock in milliseconds. * A value of 0 means there is no restriction. */ - public void setMaximumTimeToLock(ComponentName admin, long timeMs) { + public void setMaximumTimeToLock(@NonNull ComponentName admin, long timeMs) { if (mService != null) { try { mService.setMaximumTimeToLock(admin, timeMs); @@ -1837,17 +1867,17 @@ public class DevicePolicyManager { /** * Retrieve the current maximum time to unlock for all admins of this user * and its profiles or a particular one. - * @param admin The name of the admin component to check, or null to aggregate + * @param admin The name of the admin component to check, or {@code null} to aggregate * all admins. * @return time in milliseconds for the given admin or the minimum value (strictest) of * all admins if admin is null. Returns 0 if there are no restrictions. */ - public long getMaximumTimeToLock(ComponentName admin) { + public long getMaximumTimeToLock(@Nullable ComponentName admin) { return getMaximumTimeToLock(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public long getMaximumTimeToLock(ComponentName admin, int userHandle) { + public long getMaximumTimeToLock(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getMaximumTimeToLock(admin, userHandle); @@ -1922,21 +1952,20 @@ public class DevicePolicyManager { * this method; if it has not, a security exception will be thrown. * Only the first device admin can set the proxy. If a second admin attempts * to set the proxy, the {@link ComponentName} of the admin originally setting the - * proxy will be returned. If successful in setting the proxy, null will + * proxy will be returned. If successful in setting the proxy, {@code null} will * be returned. * The method can be called repeatedly by the device admin alrady setting the * proxy to update the proxy and exclusion list. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated - * with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param proxySpec the global proxy desired. Must be an HTTP Proxy. * Pass Proxy.NO_PROXY to reset the proxy. * @param exclusionList a list of domains to be excluded from the global proxy. - * @return returns null if the proxy was successfully set, or a {@link ComponentName} - * of the device admin that sets thew proxy otherwise. + * @return {@code null} if the proxy was successfully set, or otherwise a {@link ComponentName} + * of the device admin that sets the proxy. * @hide */ - public ComponentName setGlobalProxy(ComponentName admin, Proxy proxySpec, + public ComponentName setGlobalProxy(@NonNull ComponentName admin, Proxy proxySpec, List<String> exclusionList ) { if (proxySpec == null) { throw new NullPointerException(); @@ -2001,7 +2030,8 @@ public class DevicePolicyManager { * @param proxyInfo The a {@link ProxyInfo} object defining the new global * HTTP proxy. A {@code null} value will clear the global HTTP proxy. */ - public void setRecommendedGlobalProxy(ComponentName admin, ProxyInfo proxyInfo) { + public void setRecommendedGlobalProxy(@NonNull ComponentName admin, @Nullable ProxyInfo + proxyInfo) { if (mService != null) { try { mService.setRecommendedGlobalProxy(admin, proxyInfo); @@ -2013,8 +2043,8 @@ public class DevicePolicyManager { /** * Returns the component name setting the global proxy. - * @return ComponentName object of the device admin that set the global proxy, or - * null if no admin has set the proxy. + * @return ComponentName object of the device admin that set the global proxy, or {@code null} + * if no admin has set the proxy. * @hide */ public ComponentName getGlobalProxyAdmin() { @@ -2147,7 +2177,7 @@ public class DevicePolicyManager { * {@link #ENCRYPTION_STATUS_ACTIVE}. This is the value of the requests; Use * {@link #getStorageEncryptionStatus()} to query the actual device state. */ - public int setStorageEncryption(ComponentName admin, boolean encrypt) { + public int setStorageEncryption(@NonNull ComponentName admin, boolean encrypt) { if (mService != null) { try { return mService.setStorageEncryption(admin, encrypt); @@ -2167,7 +2197,7 @@ public class DevicePolicyManager { * administrators. * @return true if the admin(s) are requesting encryption, false if not. */ - public boolean getStorageEncryption(ComponentName admin) { + public boolean getStorageEncryption(@Nullable ComponentName admin) { if (mService != null) { try { return mService.getStorageEncryption(admin, UserHandle.myUserId()); @@ -2216,14 +2246,14 @@ public class DevicePolicyManager { /** * Installs the given certificate as a user CA. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use - * <code>null</code> if calling from a delegated certificate installer. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. * @param certBuffer encoded form of the certificate to install. * * @return false if the certBuffer cannot be parsed or installation is * interrupted, true otherwise. */ - public boolean installCaCert(ComponentName admin, byte[] certBuffer) { + public boolean installCaCert(@Nullable ComponentName admin, byte[] certBuffer) { if (mService != null) { try { return mService.installCaCert(admin, certBuffer); @@ -2237,11 +2267,11 @@ public class DevicePolicyManager { /** * Uninstalls the given certificate from trusted user CAs, if present. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use - * <code>null</code> if calling from a delegated certificate installer. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. * @param certBuffer encoded form of the certificate to remove. */ - public void uninstallCaCert(ComponentName admin, byte[] certBuffer) { + public void uninstallCaCert(@Nullable ComponentName admin, byte[] certBuffer) { if (mService != null) { try { final String alias = getCaCertAlias(certBuffer); @@ -2259,11 +2289,11 @@ public class DevicePolicyManager { * If a user has installed any certificates by other means than device policy these will be * included too. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use - * <code>null</code> if calling from a delegated certificate installer. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. * @return a List of byte[] arrays, each encoding one user CA certificate. */ - public List<byte[]> getInstalledCaCerts(ComponentName admin) { + public List<byte[]> getInstalledCaCerts(@Nullable ComponentName admin) { List<byte[]> certs = new ArrayList<byte[]>(); if (mService != null) { try { @@ -2287,10 +2317,10 @@ public class DevicePolicyManager { * Uninstalls all custom trusted CA certificates from the profile. Certificates installed by * means other than device policy will also be removed, except for system CA certificates. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use - * <code>null</code> if calling from a delegated certificate installer. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. */ - public void uninstallAllUserCaCerts(ComponentName admin) { + public void uninstallAllUserCaCerts(@Nullable ComponentName admin) { if (mService != null) { for (String alias : new TrustedCertificateStore().userAliases()) { try { @@ -2305,11 +2335,11 @@ public class DevicePolicyManager { /** * Returns whether this certificate is installed as a trusted CA. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use - * <code>null</code> if calling from a delegated certificate installer. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. * @param certBuffer encoded form of the certificate to look up. */ - public boolean hasCaCertInstalled(ComponentName admin, byte[] certBuffer) { + public boolean hasCaCertInstalled(@Nullable ComponentName admin, byte[] certBuffer) { if (mService != null) { try { mService.enforceCanManageCaCerts(admin); @@ -2327,21 +2357,21 @@ public class DevicePolicyManager { * Called by a device or profile owner to install a certificate and private key pair. The * keypair will be visible to all apps within the profile. * - * @param who Which {@link DeviceAdminReceiver} this request is associated with. Use - * <code>null</code> if calling from a delegated certificate installer. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. * @param privKey The private key to install. * @param cert The certificate to install. * @param alias The private key alias under which to install the certificate. If a certificate * with that alias already exists, it will be overwritten. * @return {@code true} if the keys were installed, {@code false} otherwise. */ - public boolean installKeyPair(ComponentName who, PrivateKey privKey, Certificate cert, + public boolean installKeyPair(@Nullable ComponentName admin, PrivateKey privKey, Certificate cert, String alias) { try { final byte[] pemCert = Credentials.convertToPem(cert); final byte[] pkcs8Key = KeyFactory.getInstance(privKey.getAlgorithm()) .getKeySpec(privKey, PKCS8EncodedKeySpec.class).getEncoded(); - return mService.installKeyPair(who, pkcs8Key, pemCert, alias); + return mService.installKeyPair(admin, pkcs8Key, pemCert, alias); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { @@ -2353,7 +2383,7 @@ public class DevicePolicyManager { } /** - * Returns the alias of a given CA certificate in the certificate store, or null if it + * @return the alias of a given CA certificate in the certificate store, or {@code null} if it * doesn't exist. */ private static String getCaCertAlias(byte[] certBuffer) throws CertificateException { @@ -2373,15 +2403,15 @@ public class DevicePolicyManager { * it is later cleared by calling this method with a null value or uninstallling the certificate * installer. * - * @param who Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param installerPackage The package name of the certificate installer which will be given - * access. If <code>null</code> is given the current package will be cleared. + * access. If {@code null} is given the current package will be cleared. */ - public void setCertInstallerPackage(ComponentName who, String installerPackage) - throws SecurityException { + public void setCertInstallerPackage(@NonNull ComponentName admin, @Nullable String + installerPackage) throws SecurityException { if (mService != null) { try { - mService.setCertInstallerPackage(who, installerPackage); + mService.setCertInstallerPackage(admin, installerPackage); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -2392,14 +2422,14 @@ public class DevicePolicyManager { * Called by a profile owner or device owner to retrieve the certificate installer for the * current user. null if none is set. * - * @param who Which {@link DeviceAdminReceiver} this request is associated with. - * @return The package name of the current delegated certificate installer. <code>null</code> + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @return The package name of the current delegated certificate installer, or {@code null} * if none is set. */ - public String getCertInstallerPackage(ComponentName who) throws SecurityException { + public String getCertInstallerPackage(@NonNull ComponentName admin) throws SecurityException { if (mService != null) { try { - return mService.getCertInstallerPackage(who); + return mService.getCertInstallerPackage(admin); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -2419,7 +2449,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param disabled Whether or not the camera should be disabled. */ - public void setCameraDisabled(ComponentName admin, boolean disabled) { + public void setCameraDisabled(@NonNull ComponentName admin, boolean disabled) { if (mService != null) { try { mService.setCameraDisabled(admin, disabled); @@ -2432,15 +2462,15 @@ public class DevicePolicyManager { /** * Determine whether or not the device's cameras have been disabled for this user, * either by the current admin, if specified, or all admins. - * @param admin The name of the admin component to check, or null to check if any admins + * @param admin The name of the admin component to check, or {@code null} to check whether any admins * have disabled the camera */ - public boolean getCameraDisabled(ComponentName admin) { + public boolean getCameraDisabled(@Nullable ComponentName admin) { return getCameraDisabled(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public boolean getCameraDisabled(ComponentName admin, int userHandle) { + public boolean getCameraDisabled(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getCameraDisabled(admin, userHandle); @@ -2463,7 +2493,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param disabled Whether screen capture is disabled or not. */ - public void setScreenCaptureDisabled(ComponentName admin, boolean disabled) { + public void setScreenCaptureDisabled(@NonNull ComponentName admin, boolean disabled) { if (mService != null) { try { mService.setScreenCaptureDisabled(admin, disabled); @@ -2476,15 +2506,15 @@ public class DevicePolicyManager { /** * Determine whether or not screen capture has been disabled by the current * admin, if specified, or all admins. - * @param admin The name of the admin component to check, or null to check if any admins + * @param admin The name of the admin component to check, or {@code null} to check whether any admins * have disabled screen capture. */ - public boolean getScreenCaptureDisabled(ComponentName admin) { + public boolean getScreenCaptureDisabled(@Nullable ComponentName admin) { return getScreenCaptureDisabled(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public boolean getScreenCaptureDisabled(ComponentName admin, int userHandle) { + public boolean getScreenCaptureDisabled(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getScreenCaptureDisabled(admin, userHandle); @@ -2507,7 +2537,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param required Whether auto time is set required or not. */ - public void setAutoTimeRequired(ComponentName admin, boolean required) { + public void setAutoTimeRequired(@NonNull ComponentName admin, boolean required) { if (mService != null) { try { mService.setAutoTimeRequired(admin, required); @@ -2561,7 +2591,7 @@ public class DevicePolicyManager { * {@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS}, {@link #KEYGUARD_DISABLE_FINGERPRINT}, * {@link #KEYGUARD_DISABLE_FEATURES_ALL} */ - public void setKeyguardDisabledFeatures(ComponentName admin, int which) { + public void setKeyguardDisabledFeatures(@NonNull ComponentName admin, int which) { if (mService != null) { try { mService.setKeyguardDisabledFeatures(admin, which); @@ -2574,17 +2604,17 @@ public class DevicePolicyManager { /** * Determine whether or not features have been disabled in keyguard either by the current * admin, if specified, or all admins. - * @param admin The name of the admin component to check, or null to check if any admins + * @param admin The name of the admin component to check, or {@code null} to check whether any admins * have disabled features in keyguard. * @return bitfield of flags. See {@link #setKeyguardDisabledFeatures(ComponentName, int)} * for a list. */ - public int getKeyguardDisabledFeatures(ComponentName admin) { + public int getKeyguardDisabledFeatures(@Nullable ComponentName admin) { return getKeyguardDisabledFeatures(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getKeyguardDisabledFeatures(ComponentName admin, int userHandle) { + public int getKeyguardDisabledFeatures(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getKeyguardDisabledFeatures(admin, userHandle); @@ -2598,7 +2628,8 @@ public class DevicePolicyManager { /** * @hide */ - public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing, int userHandle) { + public void setActiveAdmin(@NonNull ComponentName policyReceiver, boolean refreshing, + int userHandle) { if (mService != null) { try { mService.setActiveAdmin(policyReceiver, refreshing, userHandle); @@ -2611,15 +2642,15 @@ public class DevicePolicyManager { /** * @hide */ - public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing) { + public void setActiveAdmin(@NonNull ComponentName policyReceiver, boolean refreshing) { setActiveAdmin(policyReceiver, refreshing, UserHandle.myUserId()); } /** - * Returns the DeviceAdminInfo as defined by the administrator's package info & meta-data + * Returns the DeviceAdminInfo as defined by the administrator's package info & meta-data * @hide */ - public DeviceAdminInfo getAdminInfo(ComponentName cn) { + public DeviceAdminInfo getAdminInfo(@NonNull ComponentName cn) { ActivityInfo ai; try { ai = mContext.getPackageManager().getReceiverInfo(cn, @@ -2646,7 +2677,7 @@ public class DevicePolicyManager { /** * @hide */ - public void getRemoveWarning(ComponentName admin, RemoteCallback result) { + public void getRemoveWarning(@Nullable ComponentName admin, RemoteCallback result) { if (mService != null) { try { mService.getRemoveWarning(admin, result, UserHandle.myUserId()); @@ -2740,10 +2771,10 @@ public class DevicePolicyManager { /** * Used to determine if a particular package has been registered as a Device Owner app. * A device owner app is a special device admin that cannot be deactivated by the user, once - * activated as a device admin. It also cannot be uninstalled. To check if a particular + * activated as a device admin. It also cannot be uninstalled. To check whether a particular * package is currently registered as the device owner app, pass in the package name from * {@link Context#getPackageName()} to this method.<p/>This is useful for device - * admin apps that want to check if they are also registered as the device owner app. The + * admin apps that want to check whether they are also registered as the device owner app. The * exact mechanism by which a device admin app is registered as a device owner app is defined by * the setup process. * @param packageName the package name of the app, to compare with the registered device owner @@ -2820,19 +2851,20 @@ public class DevicePolicyManager { * MANAGE_DEVICE_ADMINS permission before the device is provisioned or by a device owner app. A * device initializer app is granted device owner privileges during device initialization and * profile owner privileges during secondary user initialization. - * @param who Which {@link DeviceAdminReceiver} this request is associated with, or null if not - * called by the device owner. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if not called by the device owner. * @param initializer Which {@link DeviceAdminReceiver} to make device initializer. * @return whether the component was successfully registered as the device initializer. * @throws IllegalArgumentException if the componentname is null or invalid * @throws IllegalStateException if the caller is not device owner or the device has * already been provisioned or a device initializer already exists. */ - public boolean setDeviceInitializer(ComponentName who, ComponentName initializer) + public boolean setDeviceInitializer(@Nullable ComponentName admin, + @NonNull ComponentName initializer) throws IllegalArgumentException, IllegalStateException { if (mService != null) { try { - return mService.setDeviceInitializer(who, initializer); + return mService.setDeviceInitializer(admin, initializer); } catch (RemoteException re) { Log.w(TAG, "Failed to set device initializer"); } @@ -2863,12 +2895,12 @@ public class DevicePolicyManager { * subsequently created users. This method can be called by either the device owner or device * initializer itself. The caller must be an active administrator. * - * @param who Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. */ - public void clearDeviceInitializerApp(ComponentName who) { + public void clearDeviceInitializerApp(@NonNull ComponentName admin) { if (mService != null) { try { - mService.clearDeviceInitializer(who); + mService.clearDeviceInitializer(admin); } catch (RemoteException re) { Log.w(TAG, "Failed to clear device initializer"); } @@ -2927,7 +2959,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @return whether the user is now enabled. */ - public boolean setUserEnabled(ComponentName admin) { + public boolean setUserEnabled(@NonNull ComponentName admin) { if (mService != null) { try { return mService.setUserEnabled(admin); @@ -2955,7 +2987,7 @@ public class DevicePolicyManager { * the user has already been set up. */ @SystemApi - public boolean setActiveProfileOwner(ComponentName admin, @Deprecated String ownerName) + public boolean setActiveProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName) throws IllegalArgumentException { if (mService != null) { try { @@ -2980,7 +3012,7 @@ public class DevicePolicyManager { * @return */ @SystemApi - public void clearProfileOwner(ComponentName admin) { + public void clearProfileOwner(@NonNull ComponentName admin) { if (mService != null) { try { mService.clearProfileOwner(admin); @@ -2992,14 +3024,14 @@ public class DevicePolicyManager { /** * @hide - * Checks if the user was already setup. + * Checks whether the user was already setup. */ public boolean hasUserSetupCompleted() { if (mService != null) { try { return mService.hasUserSetupCompleted(); } catch (RemoteException re) { - Log.w(TAG, "Failed to check if user setup has completed"); + Log.w(TAG, "Failed to check whether user setup has completed"); } } return true; @@ -3021,7 +3053,7 @@ public class DevicePolicyManager { * @throws IllegalArgumentException if admin is null, the package isn't installed, or the * preconditions mentioned are not met. */ - public boolean setProfileOwner(ComponentName admin, @Deprecated String ownerName, + public boolean setProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName, int userHandle) throws IllegalArgumentException { if (admin == null) { throw new NullPointerException("admin cannot be null"); @@ -3048,7 +3080,7 @@ public class DevicePolicyManager { * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. */ - public void setProfileEnabled(ComponentName admin) { + public void setProfileEnabled(@NonNull ComponentName admin) { if (mService != null) { try { mService.setProfileEnabled(admin); @@ -3066,12 +3098,13 @@ public class DevicePolicyManager { * @see #isProfileOwnerApp * @see #isDeviceOwnerApp * + * @param admin Which {@link DeviceAdminReceiver} this request is associate with. * @param profileName The name of the profile. */ - public void setProfileName(ComponentName who, String profileName) { + public void setProfileName(@NonNull ComponentName admin, String profileName) { if (mService != null) { try { - mService.setProfileName(who, profileName); + mService.setProfileName(admin, profileName); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -3102,7 +3135,7 @@ public class DevicePolicyManager { /** * @hide - * @return the packageName of the owner of the given user profile or null if no profile + * @return the packageName of the owner of the given user profile or {@code null} if no profile * owner has been set for that user. * @throws IllegalArgumentException if the userId is invalid. */ @@ -3130,8 +3163,8 @@ public class DevicePolicyManager { /** * @hide - * @return the human readable name of the organisation associated with this DPM or null if - * one is not set. + * @return the human readable name of the organisation associated with this DPM or {@code null} + * if one is not set. * @throws IllegalArgumentException if the userId is invalid. */ public String getProfileOwnerName() throws IllegalArgumentException { @@ -3185,8 +3218,8 @@ public class DevicePolicyManager { * @param filter The IntentFilter for which a default handler is added. * @param activity The Activity that is added as default intent handler. */ - public void addPersistentPreferredActivity(ComponentName admin, IntentFilter filter, - ComponentName activity) { + public void addPersistentPreferredActivity(@NonNull ComponentName admin, IntentFilter filter, + @NonNull ComponentName activity) { if (mService != null) { try { mService.addPersistentPreferredActivity(admin, filter, activity); @@ -3206,7 +3239,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param packageName The name of the package for which preferences are removed. */ - public void clearPackagePersistentPreferredActivities(ComponentName admin, + public void clearPackagePersistentPreferredActivities(@NonNull ComponentName admin, String packageName) { if (mService != null) { try { @@ -3241,7 +3274,7 @@ public class DevicePolicyManager { * * @see UserManager#KEY_RESTRICTIONS_PENDING */ - public void setApplicationRestrictions(ComponentName admin, String packageName, + public void setApplicationRestrictions(@NonNull ComponentName admin, String packageName, Bundle settings) { if (mService != null) { try { @@ -3271,8 +3304,8 @@ public class DevicePolicyManager { * then it's up to the TrustAgent itself to aggregate the values from all device admins. * <p>Consult documentation for the specific TrustAgent to determine legal options parameters. */ - public void setTrustAgentConfiguration(ComponentName admin, ComponentName target, - PersistableBundle configuration) { + public void setTrustAgentConfiguration(@NonNull ComponentName admin, + @NonNull ComponentName target, PersistableBundle configuration) { if (mService != null) { try { mService.setTrustAgentConfiguration(admin, target, configuration); @@ -3296,14 +3329,14 @@ public class DevicePolicyManager { * @param agent Which component to get enabled features for. * @return configuration for the given trust agent. */ - public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin, - ComponentName agent) { + public List<PersistableBundle> getTrustAgentConfiguration(@Nullable ComponentName admin, + @NonNull ComponentName agent) { return getTrustAgentConfiguration(admin, agent, UserHandle.myUserId()); } /** @hide per-user version */ - public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin, - ComponentName agent, int userHandle) { + public List<PersistableBundle> getTrustAgentConfiguration(@Nullable ComponentName admin, + @NonNull ComponentName agent, int userHandle) { if (mService != null) { try { return mService.getTrustAgentConfiguration(admin, agent, userHandle); @@ -3321,13 +3354,13 @@ public class DevicePolicyManager { * <p>The calling device admin must be a profile owner. If it is not, a * security exception will be thrown. * - * @param who Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param disabled If true caller-Id information in the managed profile is not displayed. */ - public void setCrossProfileCallerIdDisabled(ComponentName who, boolean disabled) { + public void setCrossProfileCallerIdDisabled(@NonNull ComponentName admin, boolean disabled) { if (mService != null) { try { - mService.setCrossProfileCallerIdDisabled(who, disabled); + mService.setCrossProfileCallerIdDisabled(admin, disabled); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -3341,12 +3374,12 @@ public class DevicePolicyManager { * <p>The calling device admin must be a profile owner. If it is not, a * security exception will be thrown. * - * @param who Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. */ - public boolean getCrossProfileCallerIdDisabled(ComponentName who) { + public boolean getCrossProfileCallerIdDisabled(@NonNull ComponentName admin) { if (mService != null) { try { - return mService.getCrossProfileCallerIdDisabled(who); + return mService.getCrossProfileCallerIdDisabled(admin); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -3396,15 +3429,15 @@ public class DevicePolicyManager { * <p> * This API works on managed profile only. * - * @param who Which {@link DeviceAdminReceiver} this request is associated + * @param admin Which {@link DeviceAdminReceiver} this request is associated * with. * @param disabled If true, bluetooth devices cannot access enterprise * contacts. */ - public void setBluetoothContactSharingDisabled(ComponentName who, boolean disabled) { + public void setBluetoothContactSharingDisabled(@NonNull ComponentName admin, boolean disabled) { if (mService != null) { try { - mService.setBluetoothContactSharingDisabled(who, disabled); + mService.setBluetoothContactSharingDisabled(admin, disabled); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -3420,13 +3453,13 @@ public class DevicePolicyManager { * <p> * This API works on managed profile only. * - * @param who Which {@link DeviceAdminReceiver} this request is associated + * @param admin Which {@link DeviceAdminReceiver} this request is associated * with. */ - public boolean getBluetoothContactSharingDisabled(ComponentName who) { + public boolean getBluetoothContactSharingDisabled(@NonNull ComponentName admin) { if (mService != null) { try { - return mService.getBluetoothContactSharingDisabled(who); + return mService.getBluetoothContactSharingDisabled(admin); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -3465,7 +3498,7 @@ public class DevicePolicyManager { * @param flags {@link DevicePolicyManager#FLAG_MANAGED_CAN_ACCESS_PARENT} and * {@link DevicePolicyManager#FLAG_PARENT_CAN_ACCESS_MANAGED} are supported. */ - public void addCrossProfileIntentFilter(ComponentName admin, IntentFilter filter, int flags) { + public void addCrossProfileIntentFilter(@NonNull ComponentName admin, IntentFilter filter, int flags) { if (mService != null) { try { mService.addCrossProfileIntentFilter(admin, filter, flags); @@ -3481,7 +3514,7 @@ public class DevicePolicyManager { * Only removes those that have been set by the profile owner. * @param admin Which {@link DeviceAdminReceiver} this request is associated with. */ - public void clearCrossProfileIntentFilters(ComponentName admin) { + public void clearCrossProfileIntentFilters(@NonNull ComponentName admin) { if (mService != null) { try { mService.clearCrossProfileIntentFilters(admin); @@ -3512,7 +3545,7 @@ public class DevicePolicyManager { * @return true if setting the restriction succeeded. It fail if there is * one or more non-system accessibility services enabled, that are not in the list. */ - public boolean setPermittedAccessibilityServices(ComponentName admin, + public boolean setPermittedAccessibilityServices(@NonNull ComponentName admin, List<String> packageNames) { if (mService != null) { try { @@ -3533,7 +3566,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @return List of accessiblity service package names. */ - public List<String> getPermittedAccessibilityServices(ComponentName admin) { + public List<String> getPermittedAccessibilityServices(@NonNull ComponentName admin) { if (mService != null) { try { return mService.getPermittedAccessibilityServices(admin); @@ -3591,7 +3624,7 @@ public class DevicePolicyManager { * one or more non-system input methods currently enabled that are not in * the packageNames list. */ - public boolean setPermittedInputMethods(ComponentName admin, List<String> packageNames) { + public boolean setPermittedInputMethods(@NonNull ComponentName admin, List<String> packageNames) { if (mService != null) { try { return mService.setPermittedInputMethods(admin, packageNames); @@ -3612,7 +3645,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @return List of input method package names. */ - public List<String> getPermittedInputMethods(ComponentName admin) { + public List<String> getPermittedInputMethods(@NonNull ComponentName admin) { if (mService != null) { try { return mService.getPermittedInputMethods(admin); @@ -3655,9 +3688,10 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param name the user's name * @see UserHandle - * @return the UserHandle object for the created user, or null if the user could not be created. + * @return the {@link android.os.UserHandle} object for the created user, or {@code null} if the + * user could not be created. */ - public UserHandle createUser(ComponentName admin, String name) { + public UserHandle createUser(@NonNull ComponentName admin, String name) { try { return mService.createUser(admin, name); } catch (RemoteException re) { @@ -3688,10 +3722,11 @@ public class DevicePolicyManager { * @param adminExtras Extras that will be passed to onEnable of the admin receiver * on the new user. * @see UserHandle - * @return the UserHandle object for the created user, or null if the user could not be created. + * @return the {@link android.os.UserHandle} object for the created user, or {@code null} if the + * user could not be created. */ - public UserHandle createAndInitializeUser(ComponentName admin, String name, String ownerName, - ComponentName profileOwnerComponent, Bundle adminExtras) { + public UserHandle createAndInitializeUser(@NonNull ComponentName admin, String name, + String ownerName, @NonNull ComponentName profileOwnerComponent, Bundle adminExtras) { try { return mService.createAndInitializeUser(admin, name, ownerName, profileOwnerComponent, adminExtras); @@ -3709,7 +3744,7 @@ public class DevicePolicyManager { * @param userHandle the user to remove. * @return {@code true} if the user was removed, {@code false} otherwise. */ - public boolean removeUser(ComponentName admin, UserHandle userHandle) { + public boolean removeUser(@NonNull ComponentName admin, UserHandle userHandle) { try { return mService.removeUser(admin, userHandle); } catch (RemoteException re) { @@ -3727,7 +3762,7 @@ public class DevicePolicyManager { * * @see Intent#ACTION_USER_FOREGROUND */ - public boolean switchUser(ComponentName admin, UserHandle userHandle) { + public boolean switchUser(@NonNull ComponentName admin, @Nullable UserHandle userHandle) { try { return mService.switchUser(admin, userHandle); } catch (RemoteException re) { @@ -3749,7 +3784,7 @@ public class DevicePolicyManager { * {@link DevicePolicyManager#setApplicationRestrictions} was called, or an empty {@link Bundle} * if no restrictions have been set. */ - public Bundle getApplicationRestrictions(ComponentName admin, String packageName) { + public Bundle getApplicationRestrictions(@NonNull ComponentName admin, String packageName) { if (mService != null) { try { return mService.getApplicationRestrictions(admin, packageName); @@ -3771,7 +3806,7 @@ public class DevicePolicyManager { * @param key The key of the restriction. See the constants in * {@link android.os.UserManager} for the list of keys. */ - public void addUserRestriction(ComponentName admin, String key) { + public void addUserRestriction(@NonNull ComponentName admin, String key) { if (mService != null) { try { mService.setUserRestriction(admin, key, true); @@ -3792,7 +3827,7 @@ public class DevicePolicyManager { * @param key The key of the restriction. See the constants in * {@link android.os.UserManager} for the list of keys. */ - public void clearUserRestriction(ComponentName admin, String key) { + public void clearUserRestriction(@NonNull ComponentName admin, String key) { if (mService != null) { try { mService.setUserRestriction(admin, key, false); @@ -3812,7 +3847,7 @@ public class DevicePolicyManager { * unhidden. * @return boolean Whether the hidden setting of the package was successfully updated. */ - public boolean setApplicationHidden(ComponentName admin, String packageName, + public boolean setApplicationHidden(@NonNull ComponentName admin, String packageName, boolean hidden) { if (mService != null) { try { @@ -3831,7 +3866,7 @@ public class DevicePolicyManager { * @param packageName The name of the package to retrieve the hidden status of. * @return boolean {@code true} if the package is hidden, {@code false} otherwise. */ - public boolean isApplicationHidden(ComponentName admin, String packageName) { + public boolean isApplicationHidden(@NonNull ComponentName admin, String packageName) { if (mService != null) { try { return mService.isApplicationHidden(admin, packageName); @@ -3849,7 +3884,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param packageName The package to be re-enabled in the current profile. */ - public void enableSystemApp(ComponentName admin, String packageName) { + public void enableSystemApp(@NonNull ComponentName admin, String packageName) { if (mService != null) { try { mService.enableSystemApp(admin, packageName); @@ -3868,7 +3903,7 @@ public class DevicePolicyManager { * intent will be re-enabled in the current profile. * @return int The number of activities that matched the intent and were installed. */ - public int enableSystemApp(ComponentName admin, Intent intent) { + public int enableSystemApp(@NonNull ComponentName admin, Intent intent) { if (mService != null) { try { return mService.enableSystemAppWithIntent(admin, intent); @@ -3894,7 +3929,7 @@ public class DevicePolicyManager { * @param disabled The boolean indicating that account management will be disabled (true) or * enabled (false). */ - public void setAccountManagementDisabled(ComponentName admin, String accountType, + public void setAccountManagementDisabled(@NonNull ComponentName admin, String accountType, boolean disabled) { if (mService != null) { try { @@ -3950,7 +3985,7 @@ public class DevicePolicyManager { * @see DeviceAdminReceiver#onLockTaskModeExiting(Context, Intent) * @see UserManager#DISALLOW_CREATE_WINDOWS */ - public void setLockTaskPackages(ComponentName admin, String[] packages) + public void setLockTaskPackages(@NonNull ComponentName admin, String[] packages) throws SecurityException { if (mService != null) { try { @@ -3967,7 +4002,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @hide */ - public String[] getLockTaskPackages(ComponentName admin) { + public String[] getLockTaskPackages(@NonNull ComponentName admin) { if (mService != null) { try { return mService.getLockTaskPackages(admin); @@ -4024,7 +4059,7 @@ public class DevicePolicyManager { * @param setting The name of the setting to update. * @param value The value to update the setting to. */ - public void setGlobalSetting(ComponentName admin, String setting, String value) { + public void setGlobalSetting(@NonNull ComponentName admin, String setting, String value) { if (mService != null) { try { mService.setGlobalSetting(admin, setting, value); @@ -4052,7 +4087,7 @@ public class DevicePolicyManager { * @param setting The name of the setting to update. * @param value The value to update the setting to. */ - public void setSecureSetting(ComponentName admin, String setting, String value) { + public void setSecureSetting(@NonNull ComponentName admin, String setting, String value) { if (mService != null) { try { mService.setSecureSetting(admin, setting, value); @@ -4072,7 +4107,8 @@ public class DevicePolicyManager { * {@link RestrictionsReceiver}. If this param is null, * it removes the restrictions provider previously assigned. */ - public void setRestrictionsProvider(ComponentName admin, ComponentName provider) { + public void setRestrictionsProvider(@NonNull ComponentName admin, + @Nullable ComponentName provider) { if (mService != null) { try { mService.setRestrictionsProvider(admin, provider); @@ -4088,7 +4124,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param on {@code true} to mute master volume, {@code false} to turn mute off. */ - public void setMasterVolumeMuted(ComponentName admin, boolean on) { + public void setMasterVolumeMuted(@NonNull ComponentName admin, boolean on) { if (mService != null) { try { mService.setMasterVolumeMuted(admin, on); @@ -4104,7 +4140,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @return {@code true} if master volume is muted, {@code false} if it's not. */ - public boolean isMasterVolumeMuted(ComponentName admin) { + public boolean isMasterVolumeMuted(@NonNull ComponentName admin) { if (mService != null) { try { return mService.isMasterVolumeMuted(admin); @@ -4123,7 +4159,7 @@ public class DevicePolicyManager { * @param packageName package to change. * @param uninstallBlocked true if the user shouldn't be able to uninstall the package. */ - public void setUninstallBlocked(ComponentName admin, String packageName, + public void setUninstallBlocked(@NonNull ComponentName admin, String packageName, boolean uninstallBlocked) { if (mService != null) { try { @@ -4139,16 +4175,16 @@ public class DevicePolicyManager { * Requires the caller to be the profile owner if checking a specific admin's policy. * <p> * <strong>Note:</strong> Starting from {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}, the - * behavior of this API is changed such that passing <code>null</code> as the <code>admin</code> + * behavior of this API is changed such that passing {@code null} as the {@code admin} * parameter will return if any admin has blocked the uninstallation. Before L MR1, passing - * <code>null</code> will cause a NullPointerException to be raised. + * {@code null} will cause a NullPointerException to be raised. * - * @param admin The name of the admin component whose blocking policy will be checked, or null - * to check if any admin has blocked the uninstallation. + * @param admin The name of the admin component whose blocking policy will be checked, or + * {@code null} to check whether any admin has blocked the uninstallation. * @param packageName package to check. * @return true if uninstallation is blocked. */ - public boolean isUninstallBlocked(ComponentName admin, String packageName) { + public boolean isUninstallBlocked(@Nullable ComponentName admin, String packageName) { if (mService != null) { try { return mService.isUninstallBlocked(admin, packageName); @@ -4168,7 +4204,6 @@ public class DevicePolicyManager { * provides a different widget type. * <p> * <strong>Note:</strong> By default no widget provider package is white-listed. - * </p> * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param packageName The package from which widget providers are white-listed. @@ -4177,7 +4212,7 @@ public class DevicePolicyManager { * @see #removeCrossProfileWidgetProvider(android.content.ComponentName, String) * @see #getCrossProfileWidgetProviders(android.content.ComponentName) */ - public boolean addCrossProfileWidgetProvider(ComponentName admin, String packageName) { + public boolean addCrossProfileWidgetProvider(@NonNull ComponentName admin, String packageName) { if (mService != null) { try { return mService.addCrossProfileWidgetProvider(admin, packageName); @@ -4195,7 +4230,6 @@ public class DevicePolicyManager { * android.content.ComponentName, String)}. * <p> * <strong>Note:</strong> By default no widget provider package is white-listed. - * </p> * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param packageName The package from which widget providers are no longer @@ -4205,7 +4239,7 @@ public class DevicePolicyManager { * @see #addCrossProfileWidgetProvider(android.content.ComponentName, String) * @see #getCrossProfileWidgetProviders(android.content.ComponentName) */ - public boolean removeCrossProfileWidgetProvider(ComponentName admin, String packageName) { + public boolean removeCrossProfileWidgetProvider(@NonNull ComponentName admin, String packageName) { if (mService != null) { try { return mService.removeCrossProfileWidgetProvider(admin, packageName); @@ -4226,7 +4260,7 @@ public class DevicePolicyManager { * @see #addCrossProfileWidgetProvider(android.content.ComponentName, String) * @see #removeCrossProfileWidgetProvider(android.content.ComponentName, String) */ - public List<String> getCrossProfileWidgetProviders(ComponentName admin) { + public List<String> getCrossProfileWidgetProviders(@NonNull ComponentName admin) { if (mService != null) { try { List<String> providers = mService.getCrossProfileWidgetProviders(admin); @@ -4246,7 +4280,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param icon the bitmap to set as the photo. */ - public void setUserIcon(ComponentName admin, Bitmap icon) { + public void setUserIcon(@NonNull ComponentName admin, Bitmap icon) { try { mService.setUserIcon(admin, icon); } catch (RemoteException re) { @@ -4273,16 +4307,17 @@ public class DevicePolicyManager { * Called by device owners to set a local system update policy. When a new policy is set, * {@link #ACTION_SYSTEM_UPDATE_POLICY_CHANGED} is broadcasted. * - * @param who Which {@link DeviceAdminReceiver} this request is associated with. All components - * in the device owner package can set system update policies and the most recent policy takes + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. All + * components in the device owner package can set system update policies and the + * most recent policy takes * effect. - * @param policy the new policy, or null to clear the current policy. + * @param policy the new policy, or {@code null} to clear the current policy. * @see SystemUpdatePolicy */ - public void setSystemUpdatePolicy(ComponentName who, SystemUpdatePolicy policy) { + public void setSystemUpdatePolicy(@NonNull ComponentName admin, SystemUpdatePolicy policy) { if (mService != null) { try { - mService.setSystemUpdatePolicy(who, policy); + mService.setSystemUpdatePolicy(admin, policy); } catch (RemoteException re) { Log.w(TAG, "Error calling setSystemUpdatePolicy", re); } @@ -4292,7 +4327,7 @@ public class DevicePolicyManager { /** * Retrieve a local system update policy set previously by {@link #setSystemUpdatePolicy}. * - * @return The current policy object, or null if no policy is set. + * @return The current policy object, or {@code null} if no policy is set. */ public SystemUpdatePolicy getSystemUpdatePolicy() { if (mService != null) { @@ -4319,7 +4354,7 @@ public class DevicePolicyManager { * @return {@code false} if attempting to disable the keyguard while a lock password was in * place. {@code true} otherwise. */ - public boolean setKeyguardDisabled(ComponentName admin, boolean disabled) { + public boolean setKeyguardDisabled(@NonNull ComponentName admin, boolean disabled) { try { return mService.setKeyguardDisabled(admin, disabled); } catch (RemoteException re) { @@ -4339,7 +4374,7 @@ public class DevicePolicyManager { * @return {@code false} if attempting to disable the status bar failed. * {@code true} otherwise. */ - public boolean setStatusBarDisabled(ComponentName admin, boolean disabled) { + public boolean setStatusBarDisabled(@NonNull ComponentName admin, boolean disabled) { try { return mService.setStatusBarDisabled(admin, disabled); } catch (RemoteException re) { @@ -4377,7 +4412,8 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param activity The Activity to be started by default during user setup. */ - public void setPreferredSetupActivity(ComponentName admin, ComponentName activity) { + public void setPreferredSetupActivity(@NonNull ComponentName admin, + @NonNull ComponentName activity) { try { mService.setPreferredSetupActivity(admin, activity); } catch (RemoteException re) { @@ -4395,7 +4431,7 @@ public class DevicePolicyManager { * @param policy One of the policy constants {@link #PERMISSION_POLICY_PROMPT}, * {@link #PERMISSION_POLICY_AUTO_GRANT} and {@link #PERMISSION_POLICY_AUTO_DENY}. */ - public void setPermissionPolicy(ComponentName admin, int policy) { + public void setPermissionPolicy(@NonNull ComponentName admin, int policy) { try { mService.setPermissionPolicy(admin, policy); } catch (RemoteException re) { @@ -4409,7 +4445,7 @@ public class DevicePolicyManager { * @param admin Which profile or device owner this request is associated with. * @return the current policy for future permission requests. */ - public int getPermissionPolicy(ComponentName admin) { + public int getPermissionPolicy(@NonNull ComponentName admin) { try { return mService.getPermissionPolicy(admin); } catch (RemoteException re) { @@ -4439,7 +4475,7 @@ public class DevicePolicyManager { * @see #PERMISSION_GRANT_STATE_DEFAULT * @see #PERMISSION_GRANT_STATE_GRANTED */ - public boolean setPermissionGrantState(ComponentName admin, String packageName, + public boolean setPermissionGrantState(@NonNull ComponentName admin, String packageName, String permission, int grantState) { try { return mService.setPermissionGrantState(admin, packageName, permission, grantState); @@ -4466,7 +4502,7 @@ public class DevicePolicyManager { * @see #setPermissionGrantState(ComponentName, String, String, int) * @see PackageManager#checkPermission(String, String) */ - public int getPermissionGrantState(ComponentName admin, String packageName, + public int getPermissionGrantState(@NonNull ComponentName admin, String packageName, String permission) { try { return mService.getPermissionGrantState(admin, packageName, permission); diff --git a/core/java/android/app/AssistContent.aidl b/core/java/android/app/assist/AssistContent.aidl index a6321bf..24379bb 100644 --- a/core/java/android/app/AssistContent.aidl +++ b/core/java/android/app/assist/AssistContent.aidl @@ -14,6 +14,6 @@ * limitations under the License. */ -package android.app; +package android.app.assist; parcelable AssistContent; diff --git a/core/java/android/app/assist/AssistContent.java b/core/java/android/app/assist/AssistContent.java new file mode 100644 index 0000000..c7e7330 --- /dev/null +++ b/core/java/android/app/assist/AssistContent.java @@ -0,0 +1,44 @@ +package android.app.assist; + +import android.content.Intent; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * New home for AssistContent. + */ +public final class AssistContent extends android.app.AssistContent implements Parcelable { + + /** @hide */ + public AssistContent() { + } + + public AssistContent(Parcel in) { + super(in); + } + + public Intent getIntent() { + return super.getIntent(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + public static final Parcelable.Creator<AssistContent> CREATOR + = new Parcelable.Creator<AssistContent>() { + public AssistContent createFromParcel(Parcel in) { + return new AssistContent(in); + } + + public AssistContent[] newArray(int size) { + return new AssistContent[size]; + } + }; +} diff --git a/core/java/android/app/AssistStructure.aidl b/core/java/android/app/assist/AssistStructure.aidl index 07fb2453..ae0a34c 100644 --- a/core/java/android/app/AssistStructure.aidl +++ b/core/java/android/app/assist/AssistStructure.aidl @@ -14,6 +14,6 @@ * limitations under the License. */ -package android.app; +package android.app.assist; parcelable AssistStructure; diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java new file mode 100644 index 0000000..1677e95 --- /dev/null +++ b/core/java/android/app/assist/AssistStructure.java @@ -0,0 +1,56 @@ +package android.app.assist; + +import android.app.Activity; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * New home for AssistStructure. + */ +public final class AssistStructure extends android.app.AssistStructure implements Parcelable { + + public AssistStructure() { + } + + /** @hide */ + public AssistStructure(Activity activity) { + super(activity); + } + + AssistStructure(Parcel in) { + super(in); + } + + public WindowNode getWindowNodeAt(int index) { + return super.getWindowNodeAt(index); + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel out, int flags) { + if (mHaveData) { + // This object holds its data. We want to write a send channel that the + // other side can use to retrieve that data. + if (mSendChannel == null) { + mSendChannel = new SendChannel(); + } + out.writeStrongBinder(mSendChannel); + } else { + // This object doesn't hold its data, so just propagate along its receive channel. + out.writeStrongBinder(mReceiveChannel); + } + } + + public static final Parcelable.Creator<AssistStructure> CREATOR + = new Parcelable.Creator<AssistStructure>() { + public AssistStructure createFromParcel(Parcel in) { + return new AssistStructure(in); + } + + public AssistStructure[] newArray(int size) { + return new AssistStructure[size]; + } + }; +} diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index 254408a..a9328bc 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -32,4 +32,5 @@ interface IUsageStatsManager { UsageEvents queryEvents(long beginTime, long endTime, String callingPackage); void setAppInactive(String packageName, boolean inactive, int userId); boolean isAppInactive(String packageName, int userId); + void whitelistAppTemporarily(String packageName, long duration, int userId); } diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 34699d8..c74b0f2 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -16,6 +16,7 @@ package android.app.usage; +import android.annotation.SystemApi; import android.content.Context; import android.content.pm.ParceledListSlice; import android.os.RemoteException; @@ -245,4 +246,25 @@ public final class UsageStatsManager { // fall through } } + + /** + * {@hide} + * Temporarily whitelist the specified app for a short duration. This is to allow an app + * receiving a high priority message to be able to access the network and acquire wakelocks + * even if the device is in power-save mode or the app is currently considered inactive. + * The caller must hold the CHANGE_DEVICE_IDLE_TEMP_WHITELIST permission. + * @param packageName The package name of the app to whitelist. + * @param duration Duration to whitelist the app for, in milliseconds. It is recommended that + * this be limited to 10s of seconds. Requested duration will be clamped to a few minutes. + * @param user The user for whom the package should be whitelisted. Passing in a user that is + * not the same as the caller's process will require the INTERACT_ACROSS_USERS permission. + * @see #isAppInactive(String) + */ + @SystemApi + public void whitelistAppTemporarily(String packageName, long duration, UserHandle user) { + try { + mService.whitelistAppTemporarily(packageName, duration, user.getIdentifier()); + } catch (RemoteException re) { + } + } } diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 8107a97..ab3f7bc 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -1467,10 +1467,31 @@ public final class BluetoothAdapter { * @hide */ public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException { + return listenUsingRfcommOn(channel, false); + } + + /** + * Create a listening, secure RFCOMM Bluetooth socket. + * <p>A remote device connecting to this socket will be authenticated and + * communication on this socket will be encrypted. + * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming + * connections from a listening {@link BluetoothServerSocket}. + * <p>Valid RFCOMM channels are in range 1 to 30. + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * <p>To auto assign a channel without creating a SDP record use + * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number. + * @param channel RFCOMM channel to listen on + * @param mitm enforce man-in-the-middle protection for authentication. + * @return a listening RFCOMM BluetoothServerSocket + * @throws IOException on error, for example Bluetooth not available, or + * insufficient permissions, or channel in use. + * @hide + */ + public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm) throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, true, true, channel); + BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm); int errno = socket.mSocket.bindListen(); - if(channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { + if (channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); } if (errno != 0) { @@ -1669,14 +1690,18 @@ public final class BluetoothAdapter { /** * Construct an encrypted, authenticated, L2CAP server socket. * Call #accept to retrieve connections to this socket. + * <p>To auto assign a port without creating a SDP record use + * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. + * @param port the PSM to listen on + * @param mitm enforce man-in-the-middle protection for authentication. * @return An L2CAP BluetoothServerSocket * @throws IOException On error, for example Bluetooth not available, or * insufficient permissions. * @hide */ - public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException { + public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm) throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_L2CAP, true, true, port); + BluetoothSocket.TYPE_L2CAP, true, true, port, mitm); int errno = socket.mSocket.bindListen(); if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); @@ -1691,6 +1716,21 @@ public final class BluetoothAdapter { } /** + * Construct an encrypted, authenticated, L2CAP server socket. + * Call #accept to retrieve connections to this socket. + * <p>To auto assign a port without creating a SDP record use + * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. + * @param port the PSM to listen on + * @return An L2CAP BluetoothServerSocket + * @throws IOException On error, for example Bluetooth not available, or + * insufficient permissions. + * @hide + */ + public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException { + return listenUsingL2capOn(port, false); + } + + /** * Read the local Out of Band Pairing Data * <p>Requires {@link android.Manifest.permission#BLUETOOTH} * diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java index 21024a6..a80f55c 100644 --- a/core/java/android/bluetooth/BluetoothServerSocket.java +++ b/core/java/android/bluetooth/BluetoothServerSocket.java @@ -86,6 +86,26 @@ public final class BluetoothServerSocket implements Closeable { throws IOException { mChannel = port; mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port, null); + if (port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { + mSocket.setExcludeSdp(true); + } + } + + /** + * Construct a socket for incoming connections. + * @param type type of socket + * @param auth require the remote device to be authenticated + * @param encrypt require the connection to be encrypted + * @param port remote port + * @param mitm enforce man-in-the-middle protection for authentication. + * @throws IOException On error, for example Bluetooth not available, or + * insufficient privileges + */ + /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port, + boolean mitm) + throws IOException { + mChannel = port; + mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port, null, mitm); if(port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { mSocket.setExcludeSdp(true); } diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java index 5cf2300..6ca6976 100644 --- a/core/java/android/bluetooth/BluetoothSocket.java +++ b/core/java/android/bluetooth/BluetoothSocket.java @@ -106,6 +106,7 @@ public final class BluetoothSocket implements Closeable { /*package*/ static final int SEC_FLAG_ENCRYPT = 1; /*package*/ static final int SEC_FLAG_AUTH = 1 << 1; /*package*/ static final int BTSOCK_FLAG_NO_SDP = 1 << 2; + /*package*/ static final int SEC_FLAG_AUTH_MITM = 1 << 3; private final int mType; /* one of TYPE_RFCOMM etc */ private BluetoothDevice mDevice; /* remote device */ @@ -115,7 +116,8 @@ public final class BluetoothSocket implements Closeable { private final BluetoothInputStream mInputStream; private final BluetoothOutputStream mOutputStream; private final ParcelUuid mUuid; - private boolean mExcludeSdp = false; + private boolean mExcludeSdp = false; /* when true no SPP SDP record will be created */ + private boolean mAuthMitm = false; /* when true Man-in-the-middle protection will be enabled*/ private ParcelFileDescriptor mPfd; private LocalSocket mSocket; private InputStream mSocketIS; @@ -158,6 +160,24 @@ public final class BluetoothSocket implements Closeable { */ /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, BluetoothDevice device, int port, ParcelUuid uuid) throws IOException { + this(type, fd, auth, encrypt, device, port, uuid, false); + } + + /** + * Construct a BluetoothSocket. + * @param type type of socket + * @param fd fd to use for connected socket, or -1 for a new socket + * @param auth require the remote device to be authenticated + * @param encrypt require the connection to be encrypted + * @param device remote device that this socket can connect to + * @param port remote port + * @param uuid SDP uuid + * @param mitm enforce man-in-the-middle protection. + * @throws IOException On error, for example Bluetooth not available, or + * insufficient privileges + */ + /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, + BluetoothDevice device, int port, ParcelUuid uuid, boolean mitm) throws IOException { if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type); if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1 && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { @@ -170,6 +190,7 @@ public final class BluetoothSocket implements Closeable { else mUuid = new ParcelUuid(new UUID(0, 0)); mType = type; mAuth = auth; + mAuthMitm = mitm; mEncrypt = encrypt; mDevice = device; mPort = port; @@ -201,6 +222,7 @@ public final class BluetoothSocket implements Closeable { mServiceName = s.mServiceName; mExcludeSdp = s.mExcludeSdp; + mAuthMitm = s.mAuthMitm; } private BluetoothSocket acceptSocket(String RemoteAddr) throws IOException { BluetoothSocket as = new BluetoothSocket(this); @@ -232,7 +254,7 @@ public final class BluetoothSocket implements Closeable { */ private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address, int port) throws IOException { - this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null); + this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null, false); } /** @hide */ @@ -252,6 +274,8 @@ public final class BluetoothSocket implements Closeable { flags |= SEC_FLAG_ENCRYPT; if(mExcludeSdp) flags |= BTSOCK_FLAG_NO_SDP; + if(mAuthMitm) + flags |= SEC_FLAG_AUTH_MITM; return flags; } diff --git a/core/java/android/bluetooth/SdpSapsRecord.java b/core/java/android/bluetooth/SdpSapsRecord.java new file mode 100644 index 0000000..84a29b9 --- /dev/null +++ b/core/java/android/bluetooth/SdpSapsRecord.java @@ -0,0 +1,91 @@ +/* + * 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.bluetooth; + +import android.os.Parcel; +import android.os.Parcelable; + +/** @hide */ +public class SdpSapsRecord implements Parcelable { + private final int mRfcommChannelNumber; + private final int mProfileVersion; + private final String mServiceName; + + public SdpSapsRecord(int rfcomm_channel_number, + int profile_version, + String service_name) { + this.mRfcommChannelNumber = rfcomm_channel_number; + this.mProfileVersion = profile_version; + this.mServiceName = service_name; + } + + public SdpSapsRecord(Parcel in) { + this.mRfcommChannelNumber = in.readInt(); + this.mProfileVersion = in.readInt(); + this.mServiceName = in.readString(); + } + + @Override + public int describeContents() { + return 0; + } + + public int getRfcommCannelNumber() { + return mRfcommChannelNumber; + } + + public int getProfileVersion() { + return mProfileVersion; + } + + public String getServiceName() { + return mServiceName; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(this.mRfcommChannelNumber); + dest.writeInt(this.mProfileVersion); + dest.writeString(this.mServiceName); + + } + + @Override + public String toString() { + String ret = "Bluetooth MAS SDP Record:\n"; + + if (mRfcommChannelNumber != -1) { + ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n"; + } + if (mServiceName != null) { + ret += "Service Name: " + mServiceName + "\n"; + } + if (mProfileVersion != -1) { + ret += "Profile version: " + mProfileVersion + "\n"; + } + return ret; + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public SdpSapsRecord createFromParcel(Parcel in) { + return new SdpSapsRecord(in); + } + public SdpRecord[] newArray(int size) { + return new SdpRecord[size]; + } + }; +} diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 17a8eb7..96a80e7 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -1552,23 +1552,21 @@ public abstract class ContentResolver { * * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI * for a whole class of content. - * @param notifyForDescendents If <code>true</code> changes to URIs beginning with <code>uri</code> - * will also cause notifications to be sent. If <code>false</code> only changes to the exact URI - * specified by <em>uri</em> will cause notifications to be sent. If <code>true</code>, any URI values - * at or below the specified URI will also trigger a match. + * @param notifyForDescendents When false, the observer will be notified whenever a + * change occurs to the exact URI specified by <code>uri</code> or to one of the + * URI's ancestors in the path hierarchy. When true, the observer will also be notified + * whenever a change occurs to the URI's descendants in the path hierarchy. * @param observer The object that receives callbacks when changes occur. * @see #unregisterContentObserver */ public final void registerContentObserver(Uri uri, boolean notifyForDescendents, - ContentObserver observer) - { + ContentObserver observer) { registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId()); } /** @hide - designated user version */ public final void registerContentObserver(Uri uri, boolean notifyForDescendents, - ContentObserver observer, int userHandle) - { + ContentObserver observer, int userHandle) { try { getContentService().registerContentObserver(uri, notifyForDescendents, observer.getContentObserver(), userHandle); diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index ddff782..00b8c71 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -105,6 +105,9 @@ interface IPackageManager { void updatePermissionFlags(String permissionName, String packageName, int flagMask, int flagValues, int userId); + boolean shouldShowRequestPermissionRationale(String permissionName, + String packageName, int userId); + boolean isProtectedBroadcast(String actionName); int checkSignatures(String pkg1, String pkg2); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 2ca0306..45245e4 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2539,6 +2539,19 @@ public abstract class PackageManager { @NonNull UserHandle user); /** + * Gets whether you should show UI with rationale for requesting a permission. + * You should do this only if you do not have the permission and the context in + * which the permission is requested does not clearly communicate to the user + * what would be the benefit from grating this permission. + * + * @param permission A permission your app wants to request. + * @return Whether you can show permission rationale UI. + * + * @hide + */ + public abstract boolean shouldShowRequestPermissionRationale(String permission); + + /** * Returns an {@link android.content.Intent} suitable for passing to * {@link android.app.Activity#startActivityForResult(android.content.Intent, int)} * which prompts the user to grant permissions to this application. diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java index c22ee5f..82d40d3 100644 --- a/core/java/android/hardware/camera2/CameraCaptureSession.java +++ b/core/java/android/hardware/camera2/CameraCaptureSession.java @@ -471,6 +471,17 @@ public abstract class CameraCaptureSession implements AutoCloseable { public abstract boolean isReprocessable(); /** + * Return if this capture session is constrained high speed session that is created by + * {@link CameraDevice#createConstrainedHighSpeedCaptureSession}. + * + * @return {@code true} if this session is constrained high speed capture session, + * {@code false} otherwise. + * + * @see CameraDevice#createConstrainedHighSpeedCaptureSession + */ + public abstract boolean isConstrainedHighSpeed(); + + /** * Get the input Surface associated with a reprocessable capture session. * * <p>Each reprocessable capture session has an input {@link Surface} where the reprocess diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index d5867a9..b69ca88 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -626,35 +626,54 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<Integer>("android.control.maxRegionsAf", int.class); /** - * <p>List of available high speed video size and fps range configurations - * supported by the camera device, in the format of (width, height, fps_min, fps_max).</p> - * <p>When HIGH_SPEED_VIDEO is supported in {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}, this metadata - * will list the supported high speed video size and fps range configurations. All the sizes - * listed in this configuration will be a subset of the sizes reported by {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes } for processed - * non-stalling formats.</p> - * <p>For the high speed video use case, where the application will set - * {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} to HIGH_SPEED_VIDEO in capture requests, the application must + * <p>List of available high speed video size, fps range and max batch size configurations + * supported by the camera device, in the format of (width, height, fps_min, fps_max, batch_size_max).</p> + * <p>When CONSTRAINED_HIGH_SPEED_VIDEO is supported in android.control.availableCapabilities, + * this metadata will list the supported high speed video size, fps range and max batch size + * configurations. All the sizes listed in this configuration will be a subset of the sizes + * reported by {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes } + * for processed non-stalling formats.</p> + * <p>For the high speed video use case, the application must * select the video size and fps range from this metadata to configure the recording and * preview streams and setup the recording requests. For example, if the application intends * to do high speed recording, it can select the maximum size reported by this metadata to * configure output streams. Once the size is selected, application can filter this metadata * by selected size and get the supported fps ranges, and use these fps ranges to setup the * recording requests. Note that for the use case of multiple output streams, application - * must select one unique size from this metadata to use. Otherwise a request error might - * occur.</p> - * <p>For normal video recording use case, where some application will NOT set - * {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} to HIGH_SPEED_VIDEO in capture requests, the fps ranges - * reported in this metadata must not be used to setup capture requests, or it will cause - * request error.</p> + * must select one unique size from this metadata to use (e.g., preview and recording streams + * must have the same size). Otherwise, the high speed capture session creation will fail.</p> + * <p>The min and max fps will be multiple times of 30fps.</p> + * <p>High speed video streaming extends significant performance pressue to camera hardware, + * to achieve efficient high speed streaming, the camera device may have to aggregate + * multiple frames together and send to camera device for processing where the request + * controls are same for all the frames in this batch. Max batch size indicates + * the max possible number of frames the camera device will group together for this high + * speed stream configuration. This max batch size will be used to generate a high speed + * recording request list by + * {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedRequestList }. + * The max batch size for each configuration will satisfy below conditions:</p> + * <ul> + * <li>Each max batch size will be a divisor of its corresponding fps_max / 30. For example, + * if max_fps is 300, max batch size will only be 1, 2, 5, or 10.</li> + * <li>The camera device may choose smaller internal batch size for each configuration, but + * the actual batch size will be a divisor of max batch size. For example, if the max batch + * size is 8, the actual batch size used by camera device will only be 1, 2, 4, or 8.</li> + * <li>The max batch size in each configuration entry must be no larger than 32.</li> + * </ul> + * <p>The camera device doesn't have to support batch mode to achieve high speed video recording, + * in such case, batch_size_max will be reported as 1 in each configuration entry.</p> + * <p>This fps ranges in this configuration list can only be used to create requests + * that are submitted to a high speed camera capture session created by + * {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }. + * The fps ranges reported in this metadata must not be used to setup capture requests for + * normal capture session, or it will cause request error.</p> * <p><b>Range of valid values:</b><br></p> - * <p>For each configuration, the fps_max >= 60fps.</p> + * <p>For each configuration, the fps_max >= 120fps.</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * <p><b>Limited capability</b> - * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p> * - * @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES - * @see CaptureRequest#CONTROL_SCENE_MODE * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL * @hide */ @@ -1003,12 +1022,33 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri /** * <p>Position of the camera optical center.</p> - * <p>As measured in the device sensor coordinate system, the - * position of the camera device's optical center, as a - * three-dimensional vector <code>(x,y,z)</code>.</p> - * <p>To transform a world position to a camera-device centered - * coordinate system, the position must be translated by this - * vector and then rotated by {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}.</p> + * <p>The position of the camera device's lens optical center, + * as a three-dimensional vector <code>(x,y,z)</code>, relative to the + * optical center of the largest camera device facing in the + * same direction as this camera, in the {@link android.hardware.SensorEvent Android sensor coordinate + * axes}. Note that only the axis definitions are shared with + * the sensor coordinate system, but not the origin.</p> + * <p>If this device is the largest or only camera device with a + * given facing, then this position will be <code>(0, 0, 0)</code>; a + * camera device with a lens optical center located 3 cm from + * the main sensor along the +X axis (to the right from the + * user's perspective) will report <code>(0.03, 0, 0)</code>.</p> + * <p>To transform a pixel coordinates between two cameras + * facing the same direction, first the source camera + * android.lens.radialDistortion must be corrected for. Then + * the source camera android.lens.intrinsicCalibration needs + * to be applied, followed by the {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} + * of the source camera, the translation of the source camera + * relative to the destination camera, the + * {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the destination camera, and + * finally the inverse of android.lens.intrinsicCalibration + * of the destination camera. This obtains a + * radial-distortion-free coordinate in the destination + * camera pixel coordinates.</p> + * <p>To compare this against a real image from the destination + * camera, the destination camera image then needs to be + * corrected for radial distortion before comparison or + * sampling.</p> * <p><b>Units</b>: Meters</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * @@ -1308,7 +1348,8 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * the max pipeline depth.</p> * <p>A pipeline depth of X stages is equivalent to a pipeline latency of * X frame intervals.</p> - * <p>This value will be 8 or less.</p> + * <p>This value will normally be 8 or less, however, for high speed capture session, + * the max pipeline depth will be up to 8 x size of high speed capture request list.</p> * <p>This key is available on all devices.</p> * * @see CaptureResult#REQUEST_PIPELINE_DEPTH @@ -1371,6 +1412,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}</li> * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING YUV_REPROCESSING}</li> * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT DEPTH_OUTPUT}</li> + * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO CONSTRAINED_HIGH_SPEED_VIDEO}</li> * </ul></p> * <p>This key is available on all devices.</p> * @@ -1384,6 +1426,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * @see #REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE * @see #REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING * @see #REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT + * @see #REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO */ @PublicKey public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES = diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index d02f349..006030c 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -583,6 +583,147 @@ public abstract class CameraDevice implements AutoCloseable { throws CameraAccessException; /** + * <p>Create a new constrained high speed capture session.</p> + * + * <p>The application can use normal capture session (created via {@link #createCaptureSession}) + * for high speed capture if the desired high speed FPS ranges are advertised by + * {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES}, in which case all API + * semantics associated with normal capture sessions applies.</p> + * + * <p>The method creates a specialized capture session that is only targeted at high speed + * video recording (>=120fps) use case if the camera device supports high speed video + * capability (i.e., {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} contains + * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO}). + * Therefore, it has special characteristics compared with a normal capture session:</p> + * + * <ul> + * + * <li>In addition to the output target Surface requirements specified by the + * {@link #createCaptureSession} method, an active high speed capture session will support up + * to 2 output Surfaces, though the application might choose to configure just one Surface + * (e.g., preview only). All Surfaces must be either video encoder surfaces (acquired by + * {@link android.media.MediaRecorder#getSurface} or + * {@link android.media.MediaCodec#createInputSurface}) or preview surfaces (obtained from + * {@link android.view.SurfaceView}, {@link android.graphics.SurfaceTexture} via + * {@link android.view.Surface#Surface(android.graphics.SurfaceTexture)}). The Surface sizes + * must be one of the sizes reported by {@link StreamConfigurationMap#getHighSpeedVideoSizes}. + * When multiple Surfaces are configured, their size must be same.</li> + * + * <li>An active high speed capture session only accepts request lists created via + * {@link #createConstrainedHighSpeedRequestList}, and the request list can only be submitted + * to this session via {@link CameraCaptureSession#captureBurst captureBurst}, or + * {@link CameraCaptureSession#setRepeatingBurst setRepeatingBurst}.</li> + * + * <li>The FPS ranges being requested to this session must be selected from + * {@link StreamConfigurationMap#getHighSpeedVideoFpsRangesFor}. The application can still use + * {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE} to control the desired FPS range. + * Switching to an FPS range that has different + * {@link android.util.Range#getUpper() maximum FPS} may trigger some camera device + * reconfigurations, which may introduce extra latency. It is recommended that the + * application avoids unnecessary maximum target FPS changes as much as possible during high + * speed streaming.</li> + * + * <li>For the request lists submitted to this session, the camera device will override the + * {@link CaptureRequest#CONTROL_MODE control mode}, auto-exposure (AE), auto-white balance + * (AWB) and auto-focus (AF) to {@link CameraMetadata#CONTROL_MODE_AUTO}, + * {@link CameraMetadata#CONTROL_AE_MODE_ON}, {@link CameraMetadata#CONTROL_AWB_MODE_AUTO} + * and {@link CameraMetadata#CONTROL_AF_MODE_CONTINUOUS_VIDEO}, respectively. All + * post-processing block mode controls will be overridden to be FAST. Therefore, no manual + * control of capture and post-processing parameters is possible. Beside these, only a subset + * of controls will work, see + * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO} for + * more details.</li> + * + * </ul> + * + * @param outputs The new set of Surfaces that should be made available as + * targets for captured high speed image data. + * @param callback The callback to notify about the status of the new capture session. + * @param handler The handler on which the callback should be invoked, or {@code null} to use + * the current thread's {@link android.os.Looper looper}. + * + * @throws IllegalArgumentException if the set of output Surfaces do not meet the requirements, + * the callback is null, or the handler is null but the current + * thread has no looper, or the camera device doesn't support + * high speed video capability. + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if the camera device has been closed + * + * @see #createCaptureSession + * @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE + * @see StreamConfigurationMap#getHighSpeedVideoSizes + * @see StreamConfigurationMap#getHighSpeedVideoFpsRangesFor + * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES + * @see CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO + * @see CameraCaptureSession#captureBurst + * @see CameraCaptureSession#setRepeatingBurst + * @see #createConstrainedHighSpeedRequestList + */ + public abstract void createConstrainedHighSpeedCaptureSession(@NonNull List<Surface> outputs, + @NonNull CameraCaptureSession.StateCallback callback, + @Nullable Handler handler) + throws CameraAccessException; + + + /** + * <p>Create a unmodifiable list of requests that is suitable for constrained high speed capture + * session streaming.</p> + * + * <p>High speed video streaming creates significant performance pressue on the camera device, + * so to achieve efficient high speed streaming, the camera device may have to aggregate + * multiple frames together. This means requests must be sent in batched groups, with all + * requests sharing the same settings. This method takes the list of output target + * Surfaces (subject to the output Surface requirements specified by the contrained high speed + * session) and a {@link CaptureRequest request}, and generates a request list that has the same + * controls for each request. The input {@link CaptureRequest request} must contain the target + * output Surfaces and target high speed FPS range that is one of the + * {@link StreamConfigurationMap#getHighSpeedVideoFpsRangesFor} for the Surface size.</p> + * + * <p>If both preview and recording Surfaces are specified in the {@code request}, the + * {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE target FPS range} in the input + * {@link CaptureRequest request} must be a fixed framerate FPS range, where the + * {@link android.util.Range#getLower minimal FPS} == + * {@link android.util.Range#getUpper() maximum FPS}. The created request list will contain + * a interleaved request pattern such that the preview output FPS is at least 30fps, the + * recording output FPS is {@link android.util.Range#getUpper() maximum FPS} of the requested + * FPS range. The application can submit this request list directly to an active high speed + * capture session to achieve high speed video recording. When only preview or recording + * Surface is specified, this method will return a list of request that have the same controls + * and output targets for all requests.</p> + * + * <p>Submitting a request list created by this method to a normal capture session will result + * in an {@link IllegalArgumentException} if the high speed + * {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE FPS range} is not supported by + * {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES}.</p> + * + * @param request The high speed capture request that will be used to generate the high speed + * request list. + * @return A unmodifiable CaptureRequest list that is suitable for constrained high speed + * capture. + * + * @throws IllegalArgumentException if the set of output Surfaces in the request do not meet the + * high speed video capability requirements, or the camera + * device doesn't support high speed video capability, or the + * request doesn't meet the high speed video capability + * requirements, or the request doesn't contain the required + * controls for high speed capture. + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if the camera device has been closed + * + * @see #createConstrainedHighSpeedCaptureSession + * @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE + * @see StreamConfigurationMap#getHighSpeedVideoSizes + * @see StreamConfigurationMap#getHighSpeedVideoFpsRangesFor + * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES + * @see CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO + */ + @NonNull + public abstract List<CaptureRequest> createConstrainedHighSpeedRequestList( + @NonNull CaptureRequest request)throws CameraAccessException; + + /** * <p>Create a {@link CaptureRequest.Builder} for new capture requests, * initialized with template for a target use case. The settings are chosen * to be the best options for the specific camera device, so it is not diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 0f002a9..0fb6889 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -802,12 +802,9 @@ public final class CameraManager { */ public ICameraService getCameraService() { synchronized(mLock) { + connectCameraServiceLocked(); if (mCameraService == null) { - Log.i(TAG, "getCameraService: Reconnecting to camera service"); - connectCameraServiceLocked(); - if (mCameraService == null) { - Log.e(TAG, "Camera service is unavailable"); - } + Log.e(TAG, "Camera service is unavailable"); } return mCameraService; } @@ -815,11 +812,16 @@ public final class CameraManager { /** * Connect to the camera service if it's available, and set up listeners. + * If the service is already connected, do nothing. * * <p>Sets mCameraService to a valid pointer or null if the connection does not succeed.</p> */ private void connectCameraServiceLocked() { - mCameraService = null; + // Only reconnect if necessary + if (mCameraService != null) return; + + Log.i(TAG, "Connecting to camera service"); + IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME); if (cameraServiceBinder == null) { // Camera service is now down, leave mCameraService as null @@ -1098,6 +1100,8 @@ public final class CameraManager { */ public void registerAvailabilityCallback(AvailabilityCallback callback, Handler handler) { synchronized (mLock) { + connectCameraServiceLocked(); + Handler oldHandler = mCallbackMap.put(callback, handler); // For new callbacks, provide initial availability information if (oldHandler == null) { @@ -1120,6 +1124,8 @@ public final class CameraManager { public void registerTorchCallback(TorchCallback callback, Handler handler) { synchronized(mLock) { + connectCameraServiceLocked(); + Handler oldHandler = mTorchCallbackMap.put(callback, handler); // For new callbacks, provide initial torch information if (oldHandler == null) { diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index ac29f80..f8db6d9 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -648,6 +648,100 @@ public abstract class CameraMetadata<TKey> { */ public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8; + /** + * <p>The device supports constrained high speed video recording (frame rate >=120fps) + * use case. The camera device will support high speed capture session created by + * {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }, which + * only accepts high speed request list created by + * {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedRequestList }.</p> + * <p>A camera device can still support high speed video streaming by advertising the high speed + * FPS ranges in {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES android.control.aeAvailableTargetFpsRanges}. For this case, all normal + * capture request per frame control and synchronization requirements will apply to + * the high speed fps ranges, the same as all other fps ranges. This capability describes + * the capability of a specialized operating mode with many limitations (see below), which + * is only targeted at high speed video recording.</p> + * <p>The supported high speed video sizes and fps ranges are specified in + * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoFpsRanges }. + * To get desired output frame rates, the application is only allowed to select video size + * and FPS range combinations provided by + * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoSizes }. + * The fps range can be controlled via {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange}.</p> + * <p>In this capability, the camera device will override aeMode, awbMode, and afMode to + * ON, ON, and CONTINUOUS_VIDEO, respectively. All post-processing block mode + * controls will be overridden to be FAST. Therefore, no manual control of capture + * and post-processing parameters is possible. All other controls operate the + * same as when {@link CaptureRequest#CONTROL_MODE android.control.mode} == AUTO. This means that all other + * android.control.* fields continue to work, such as</p> + * <ul> + * <li>{@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange}</li> + * <li>{@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION android.control.aeExposureCompensation}</li> + * <li>{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock}</li> + * <li>{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock}</li> + * <li>{@link CaptureRequest#CONTROL_EFFECT_MODE android.control.effectMode}</li> + * <li>{@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions}</li> + * <li>{@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}</li> + * <li>{@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions}</li> + * <li>{@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}</li> + * <li>{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}</li> + * </ul> + * <p>Outside of android.control.*, the following controls will work:</p> + * <ul> + * <li>{@link CaptureRequest#FLASH_MODE android.flash.mode} (TORCH mode only, automatic flash for still capture will not + * work since aeMode is ON)</li> + * <li>{@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode} (if it is supported)</li> + * <li>{@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}</li> + * <li>{@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} (if it is supported)</li> + * </ul> + * <p>For high speed recording use case, the actual maximum supported frame rate may + * be lower than what camera can output, depending on the destination Surfaces for + * the image data. For example, if the destination surface is from video encoder, + * the application need check if the video encoder is capable of supporting the + * high frame rate for a given video size, or it will end up with lower recording + * frame rate. If the destination surface is from preview window, the actual preview frame + * rate will be bounded by the screen refresh rate.</p> + * <p>The camera device will only support up to 2 high speed simultaneous output surfaces + * (preview and recording surfaces) + * in this mode. Above controls will be effective only if all of below conditions are true:</p> + * <ul> + * <li>The application creates a camera capture session with no more than 2 surfaces via + * {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }. The + * targeted surfaces must be preview surface (either from + * {@link android.view.SurfaceView } or {@link android.graphics.SurfaceTexture }) or + * recording surface(either from {@link android.media.MediaRecorder#getSurface } or + * {@link android.media.MediaCodec#createInputSurface }).</li> + * <li>The stream sizes are selected from the sizes reported by + * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoSizes }.</li> + * <li>The FPS ranges are selected from + * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoFpsRanges }.</li> + * </ul> + * <p>When above conditions are NOT satistied, the + * {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession } + * and {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedRequestList } will fail.</p> + * <p>Switching to a FPS range that has different maximum FPS may trigger some camera device + * reconfigurations, which may introduce extra latency. It is recommended that + * the application avoids unnecessary maximum target FPS changes as much as possible + * during high speed streaming.</p> + * + * @see CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES + * @see CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION + * @see CaptureRequest#CONTROL_AE_LOCK + * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER + * @see CaptureRequest#CONTROL_AE_REGIONS + * @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE + * @see CaptureRequest#CONTROL_AF_REGIONS + * @see CaptureRequest#CONTROL_AF_TRIGGER + * @see CaptureRequest#CONTROL_AWB_LOCK + * @see CaptureRequest#CONTROL_AWB_REGIONS + * @see CaptureRequest#CONTROL_EFFECT_MODE + * @see CaptureRequest#CONTROL_MODE + * @see CaptureRequest#FLASH_MODE + * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE + * @see CaptureRequest#SCALER_CROP_REGION + * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE + * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES + */ + public static final int REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO = 9; + // // Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE // @@ -1725,6 +1819,10 @@ public abstract class CameraMetadata<TKey> { public static final int CONTROL_SCENE_MODE_BARCODE = 16; /** + * <p>This is deprecated, please use + * {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession } + * and {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedRequestList } + * for high speed video recording.</p> * <p>Optimized for high speed video recording (frame rate >=60fps) use case.</p> * <p>The supported high speed video sizes and fps ranges are specified in * android.control.availableHighSpeedVideoConfigurations. To get desired @@ -1799,6 +1897,7 @@ public abstract class CameraMetadata<TKey> { * @see CaptureRequest#SCALER_CROP_REGION * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE * @see CaptureRequest#CONTROL_SCENE_MODE + * @deprecated Please refer to this API documentation to find the alternatives */ public static final int CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO = 17; diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index df6c986..3bb2fdb 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -2584,12 +2584,33 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { /** * <p>Position of the camera optical center.</p> - * <p>As measured in the device sensor coordinate system, the - * position of the camera device's optical center, as a - * three-dimensional vector <code>(x,y,z)</code>.</p> - * <p>To transform a world position to a camera-device centered - * coordinate system, the position must be translated by this - * vector and then rotated by {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}.</p> + * <p>The position of the camera device's lens optical center, + * as a three-dimensional vector <code>(x,y,z)</code>, relative to the + * optical center of the largest camera device facing in the + * same direction as this camera, in the {@link android.hardware.SensorEvent Android sensor coordinate + * axes}. Note that only the axis definitions are shared with + * the sensor coordinate system, but not the origin.</p> + * <p>If this device is the largest or only camera device with a + * given facing, then this position will be <code>(0, 0, 0)</code>; a + * camera device with a lens optical center located 3 cm from + * the main sensor along the +X axis (to the right from the + * user's perspective) will report <code>(0.03, 0, 0)</code>.</p> + * <p>To transform a pixel coordinates between two cameras + * facing the same direction, first the source camera + * android.lens.radialDistortion must be corrected for. Then + * the source camera android.lens.intrinsicCalibration needs + * to be applied, followed by the {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} + * of the source camera, the translation of the source camera + * relative to the destination camera, the + * {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the destination camera, and + * finally the inverse of android.lens.intrinsicCalibration + * of the destination camera. This obtains a + * radial-distortion-free coordinate in the destination + * camera pixel coordinates.</p> + * <p>To compare this against a real image from the destination + * camera, the destination camera image then needs to be + * corrected for radial distortion before comparison or + * sampling.</p> * <p><b>Units</b>: Meters</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java index 7a39dd5..ab0f607 100644 --- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java @@ -721,4 +721,10 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { } } + @Override + public boolean isConstrainedHighSpeed() { + // TODO: to be implemented + return false; + } + } diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index e60e266..ad0cd0f 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -906,7 +906,6 @@ public class CameraDeviceImpl extends CameraDevice { } mRemoteDevice = null; - mInError = false; } } @@ -1889,13 +1888,13 @@ public class CameraDeviceImpl extends CameraDevice { } private void checkIfCameraClosedOrInError() throws CameraAccessException { + if (mRemoteDevice == null) { + throw new IllegalStateException("CameraDevice was already closed"); + } if (mInError) { throw new CameraAccessException(CameraAccessException.CAMERA_ERROR, "The camera device has encountered a serious error"); } - if (mRemoteDevice == null) { - throw new IllegalStateException("CameraDevice was already closed"); - } } /** Whether the camera device has started to close (may not yet have finished) */ @@ -1906,4 +1905,18 @@ public class CameraDeviceImpl extends CameraDevice { private CameraCharacteristics getCharacteristics() { return mCharacteristics; } + + @Override + public void createConstrainedHighSpeedCaptureSession(List<Surface> outputs, + android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler) + throws CameraAccessException { + // TODO: to be implemented + throw new UnsupportedOperationException("To be implemented!!!!"); + } + + @Override + public List<CaptureRequest> createConstrainedHighSpeedRequestList(CaptureRequest request) + throws CameraAccessException { + throw new UnsupportedOperationException("To be implemented!!!!"); + } } diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableHighSpeedVideoConfiguration.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableHighSpeedVideoConfiguration.java index c03144b..2449abe 100644 --- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableHighSpeedVideoConfiguration.java +++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableHighSpeedVideoConfiguration.java @@ -33,7 +33,7 @@ import java.nio.ByteBuffer; */ public class MarshalQueryableHighSpeedVideoConfiguration implements MarshalQueryable<HighSpeedVideoConfiguration> { - private static final int SIZE = SIZEOF_INT32 * 4; + private static final int SIZE = SIZEOF_INT32 * 5; private class MarshalerHighSpeedVideoConfiguration extends Marshaler<HighSpeedVideoConfiguration> { @@ -49,6 +49,7 @@ public class MarshalQueryableHighSpeedVideoConfiguration buffer.putInt(value.getHeight()); buffer.putInt(value.getFpsMin()); buffer.putInt(value.getFpsMax()); + buffer.putInt(value.getBatchSizeMax()); } @Override @@ -57,8 +58,9 @@ public class MarshalQueryableHighSpeedVideoConfiguration int height = buffer.getInt(); int fpsMin = buffer.getInt(); int fpsMax = buffer.getInt(); + int batchSizeMax = buffer.getInt(); - return new HighSpeedVideoConfiguration(width, height, fpsMin, fpsMax); + return new HighSpeedVideoConfiguration(width, height, fpsMin, fpsMax, batchSizeMax); } @Override diff --git a/core/java/android/hardware/camera2/params/HighSpeedVideoConfiguration.java b/core/java/android/hardware/camera2/params/HighSpeedVideoConfiguration.java index 088049f..b469126 100644 --- a/core/java/android/hardware/camera2/params/HighSpeedVideoConfiguration.java +++ b/core/java/android/hardware/camera2/params/HighSpeedVideoConfiguration.java @@ -33,6 +33,7 @@ import android.util.Size; * @hide */ public final class HighSpeedVideoConfiguration { + static final private int HIGH_SPEED_MAX_MINIMAL_FPS = 120; /** * Create a new {@link HighSpeedVideoConfiguration}. @@ -48,15 +49,18 @@ public final class HighSpeedVideoConfiguration { * @hide */ public HighSpeedVideoConfiguration( - final int width, final int height, final int fpsMin, final int fpsMax) { - if (fpsMax < 60) { - throw new IllegalArgumentException("fpsMax must be at least 60"); + final int width, final int height, final int fpsMin, final int fpsMax, + final int batchSizeMax) { + if (fpsMax < HIGH_SPEED_MAX_MINIMAL_FPS) { + throw new IllegalArgumentException("fpsMax must be at least " + + HIGH_SPEED_MAX_MINIMAL_FPS); } mFpsMax = fpsMax; mWidth = checkArgumentPositive(width, "width must be positive"); mHeight = checkArgumentPositive(height, "height must be positive"); mFpsMin = checkArgumentPositive(fpsMin, "fpsMin must be positive"); mSize = new Size(mWidth, mHeight); + mBatchSizeMax = checkArgumentPositive(batchSizeMax, "batchSizeMax must be positive"); mFpsRange = new Range<Integer>(mFpsMin, mFpsMax); } @@ -106,9 +110,18 @@ public final class HighSpeedVideoConfiguration { } /** + * Convenience method to return the max batch size of this high speed video configuration. + * + * @return the maximal batch size for this high speed video configuration + */ + public int getBatchSizeMax() { + return mBatchSizeMax; + } + + /** * Convenience method to return the FPS range of this high speed video configuration. * - * @return a Range with high bound >= 60 + * @return a Range with high bound >= {@value #HIGH_SPEED_MAX_MINIMAL_FPS} */ public Range<Integer> getFpsRange() { return mFpsRange; @@ -135,7 +148,8 @@ public final class HighSpeedVideoConfiguration { return mWidth == other.mWidth && mHeight == other.mHeight && mFpsMin == other.mFpsMin && - mFpsMax == other.mFpsMax; + mFpsMax == other.mFpsMax && + mBatchSizeMax == other.mBatchSizeMax; } return false; } @@ -152,6 +166,7 @@ public final class HighSpeedVideoConfiguration { private final int mHeight; private final int mFpsMin; private final int mFpsMax; + private final int mBatchSizeMax; private final Size mSize; private final Range<Integer> mFpsRange; } diff --git a/core/java/android/net/IpReachabilityMonitor.java b/core/java/android/net/IpReachabilityMonitor.java index 3cfd8b2..88fb014 100644 --- a/core/java/android/net/IpReachabilityMonitor.java +++ b/core/java/android/net/IpReachabilityMonitor.java @@ -99,16 +99,10 @@ public class IpReachabilityMonitor { public static boolean probeNeighbor(int ifIndex, InetAddress ip) { final long IO_TIMEOUT = 300L; final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex; - // This currently does not cause neighbor probing if the target |ip| - // has been confirmed reachable within the past "delay_probe_time" - // seconds, i.e. within the past 5 seconds. - // - // TODO: replace with a transition directly to NUD_PROBE state once - // kernels are updated to do so correctly. if (DBG) { Log.d(TAG, msgSnippet); } final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage( - 1, ip, StructNdMsg.NUD_DELAY, ifIndex, null); + 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null); boolean returnValue = false; try (NetlinkSocket nlSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE)) { diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl index 602bfea..268295d 100644 --- a/core/java/android/os/IDeviceIdleController.aidl +++ b/core/java/android/os/IDeviceIdleController.aidl @@ -16,6 +16,8 @@ package android.os; +import android.os.UserHandle; + /** @hide */ interface IDeviceIdleController { void addPowerSaveWhitelistApp(String name); @@ -23,5 +25,7 @@ interface IDeviceIdleController { String[] getSystemPowerWhitelist(); String[] getFullPowerWhitelist(); int[] getAppIdWhitelist(); + int[] getAppIdTempWhitelist(); boolean isPowerSaveWhitelistApp(String name); + void addPowerSaveTempWhitelistApp(String name, long duration, int userId); } diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 1d9d7d2..8b18f32 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -928,6 +928,14 @@ public final class PowerManager { = "android.os.action.POWER_SAVE_WHITELIST_CHANGED"; /** + * @hide Intent that is broadcast when the set of temporarily whitelisted apps has changed. + * This broadcast is only sent to registered receivers. + */ + @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED + = "android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED"; + + /** * Intent that is broadcast when the state of {@link #isPowerSaveMode()} is about to change. * This broadcast is only sent to registered receivers. * diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java index e523285..e742f98 100644 --- a/core/java/android/os/PowerManagerInternal.java +++ b/core/java/android/os/PowerManagerInternal.java @@ -137,6 +137,8 @@ public abstract class PowerManagerInternal { public abstract void setDeviceIdleWhitelist(int[] appids); + public abstract void setDeviceIdleTempWhitelist(int[] appids); + public abstract void updateUidProcState(int uid, int procState); public abstract void uidGone(int uid); diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 76a5f967..df2e5f9 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -7930,8 +7930,6 @@ public final class ContactsContract { /** * API for inquiring about the general status of the provider. - * - * @hide */ public static final class ProviderStatus { @@ -7965,21 +7963,16 @@ public final class ContactsContract { public static final int STATUS_NORMAL = 0; /** - * The status used when the provider is in the process of upgrading. Contacts - * are temporarily unaccessible. - */ - public static final int STATUS_UPGRADING = 1; - - /** - * The status used during a locale change. + * The provider won't respond to queries. It is in the middle of a long running task, such + * as a database upgrade or locale change. */ - public static final int STATUS_CHANGING_LOCALE = 3; + public static final int STATUS_BUSY = 1; /** * The status that indicates that there are no accounts and no contacts * on the device. */ - public static final int STATUS_NO_ACCOUNTS_NO_CONTACTS = 4; + public static final int STATUS_EMPTY = 2; } /** diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 7565654b..51dbdee 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -22,6 +22,7 @@ import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; +import android.content.Intent; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteException; @@ -33,6 +34,7 @@ import android.media.ThumbnailUtils; import android.net.Uri; import android.os.Environment; import android.os.ParcelFileDescriptor; +import android.service.media.CameraPrewarmService; import android.util.Log; import java.io.FileInputStream; @@ -226,33 +228,24 @@ public final class MediaStore { public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA"; /** - * The name of the Intent action used to indicate that a camera launch might be imminent. This - * broadcast should be targeted to the package that is receiving - * {@link #INTENT_ACTION_STILL_IMAGE_CAMERA} or - * {@link #INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE}, depending on the context. If such - * intent would launch the resolver activity, this broadcast should not be sent at all. + * Name under which an activity handling {@link #INTENT_ACTION_STILL_IMAGE_CAMERA} or + * {@link #INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE} publishes the service name for its prewarm + * service. * <p> - * A receiver of this broadcast should do the absolute minimum amount of work to initialize the - * camera in order to reduce startup time in likely case that shortly after an actual camera - * launch intent would be sent. + * This meta-data should reference the fully qualified class name of the prewarm service + * extending {@link CameraPrewarmService}. * <p> - * In case the actual intent will not be fired, the target package will receive - * {@link #ACTION_STILL_IMAGE_CAMERA_COOLDOWN}. However, it is recommended that the receiver - * also implements a timeout to close the camera after receiving this intent, as there is no - * guarantee that {@link #ACTION_STILL_IMAGE_CAMERA_COOLDOWN} will be delivered. - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_STILL_IMAGE_CAMERA_PREWARM = "android.media.action.STILL_IMAGE_CAMERA_PREWARM"; - - /** - * The name of the Intent action used to indicate that an imminent camera launch has been - * cancelled by the user. This broadcast should be targeted to the package that has received - * {@link #ACTION_STILL_IMAGE_CAMERA_PREWARM}. + * The prewarm service will get bound and receive a prewarm signal + * {@link CameraPrewarmService#onPrewarm()} when a camera launch intent fire might be imminent. + * An application implementing a prewarm service should do the absolute minimum amount of work + * to initialize the camera in order to reduce startup time in likely case that shortly after a + * camera launch intent would be sent. * <p> - * A receiver of this broadcast should close the camera immediately. + * If the camera launch intent gets fired shortly after, the service will be unbound + * asynchronously, without receiving */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_STILL_IMAGE_CAMERA_COOLDOWN = "android.media.action.STILL_IMAGE_CAMERA_COOLDOWN"; + public static final String META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE = + "android.media.still_image_camera_preview_service"; /** * The name of the Intent action used to launch a camera in still image mode @@ -2268,5 +2261,4 @@ public final class MediaStore { } return null; } - } diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl index 30ea8e7..409542d 100644 --- a/core/java/android/security/IKeystoreService.aidl +++ b/core/java/android/security/IKeystoreService.aidl @@ -65,9 +65,10 @@ interface IKeystoreService { ExportResult exportKey(String alias, int format, in KeymasterBlob clientId, in KeymasterBlob appId); OperationResult begin(IBinder appToken, String alias, int purpose, boolean pruneable, - in KeymasterArguments params, in byte[] entropy, out KeymasterArguments operationParams); + in KeymasterArguments params, in byte[] entropy); OperationResult update(IBinder token, in KeymasterArguments params, in byte[] input); - OperationResult finish(IBinder token, in KeymasterArguments params, in byte[] signature); + OperationResult finish(IBinder token, in KeymasterArguments params, in byte[] signature, + in byte[] entropy); int abort(IBinder handle); boolean isOperationAuthorized(IBinder token); int addAuthToken(in byte[] authToken); diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index 0e2b8ba..6e40c6c 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -50,8 +50,7 @@ public final class KeymasterDefs { public static final int KM_TAG_BLOCK_MODE = KM_ENUM_REP | 4; 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_RETURN_UNAUTHED = KM_BOOL | 7; - public static final int KM_TAG_CALLER_NONCE = KM_BOOL | 8; + public static final int KM_TAG_CALLER_NONCE = KM_BOOL | 7; public static final int KM_TAG_RESCOPING_ADD = KM_ENUM_REP | 101; public static final int KM_TAG_RESCOPING_DEL = KM_ENUM_REP | 102; @@ -82,7 +81,7 @@ public final class KeymasterDefs { public static final int KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000; public static final int KM_TAG_NONCE = KM_BYTES | 1001; - public static final int KM_TAG_CHUNK_LENGTH = KM_INT | 1002; + public static final int KM_TAG_AEAD_TAG = KM_BYTES | 1002; public static final int KM_TAG_AUTH_TOKEN = KM_BYTES | 1003; public static final int KM_TAG_MAC_LENGTH = KM_INT | 1004; @@ -93,12 +92,10 @@ public final class KeymasterDefs { public static final int KM_ALGORITHM_HMAC = 128; // Block modes. - public static final int KM_MODE_FIRST_UNAUTHENTICATED = 1; - public static final int KM_MODE_ECB = KM_MODE_FIRST_UNAUTHENTICATED; + public static final int KM_MODE_ECB = 1; public static final int KM_MODE_CBC = 2; - public static final int KM_MODE_CTR = 4; - public static final int KM_MODE_FIRST_AUTHENTICATED = 32; - public static final int KM_MODE_GCM = KM_MODE_FIRST_AUTHENTICATED; + public static final int KM_MODE_CTR = 3; + public static final int KM_MODE_GCM = 32; // Padding modes. public static final int KM_PAD_NONE = 1; @@ -194,7 +191,7 @@ public final class KeymasterDefs { public static final int KM_ERROR_UNSUPPORTED_EC_FIELD = -50; public static final int KM_ERROR_MISSING_NONCE = -51; public static final int KM_ERROR_INVALID_NONCE = -52; - public static final int KM_ERROR_UNSUPPORTED_CHUNK_LENGTH = -53; + public static final int KM_ERROR_MISSING_MAC_LENGTH = -53; public static final int KM_ERROR_RESCOPABLE_KEY_NOT_USABLE = -54; public static final int KM_ERROR_CALLER_NONCE_PROHIBITED = -55; public static final int KM_ERROR_UNIMPLEMENTED = -100; diff --git a/core/java/android/security/keymaster/OperationResult.java b/core/java/android/security/keymaster/OperationResult.java index 9b46ad3..911a05a 100644 --- a/core/java/android/security/keymaster/OperationResult.java +++ b/core/java/android/security/keymaster/OperationResult.java @@ -31,6 +31,7 @@ public class OperationResult implements Parcelable { public final long operationHandle; public final int inputConsumed; public final byte[] output; + public final KeymasterArguments outParams; public static final Parcelable.Creator<OperationResult> CREATOR = new Parcelable.Creator<OperationResult>() { @@ -49,6 +50,7 @@ public class OperationResult implements Parcelable { operationHandle = in.readLong(); inputConsumed = in.readInt(); output = in.createByteArray(); + outParams = KeymasterArguments.CREATOR.createFromParcel(in); } @Override @@ -63,5 +65,6 @@ public class OperationResult implements Parcelable { out.writeLong(operationHandle); out.writeInt(inputConsumed); out.writeByteArray(output); + outParams.writeToParcel(out, flags); } } diff --git a/core/java/android/service/carrier/CarrierService.java b/core/java/android/service/carrier/CarrierService.java index 15ccc25..4a4a375 100644 --- a/core/java/android/service/carrier/CarrierService.java +++ b/core/java/android/service/carrier/CarrierService.java @@ -86,11 +86,13 @@ public abstract class CarrierService extends Service { /** @hide */ @Override public final IBinder onBind(Intent intent) { - if (!CONFIG_SERVICE_INTERFACE.equals(intent.getAction()) - || !BIND_SERVICE_INTERFACE.equals(intent.getAction())) { - return null; + switch (intent.getAction()) { + case CONFIG_SERVICE_INTERFACE: + case BIND_SERVICE_INTERFACE: + return mStubWrapper; + default: + return null; } - return mStubWrapper; } /** diff --git a/core/java/android/service/media/CameraPrewarmService.java b/core/java/android/service/media/CameraPrewarmService.java new file mode 100644 index 0000000..335b00a --- /dev/null +++ b/core/java/android/service/media/CameraPrewarmService.java @@ -0,0 +1,96 @@ +/* + * 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.service.media; + +import android.app.Service; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; + +/** + * Extend this class to implement a camera prewarm service. See + * {@link android.provider.MediaStore#META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE}. + */ +public abstract class CameraPrewarmService extends Service { + + /** + * Intent action to bind the service as a prewarm service. + * @hide + */ + public static final String ACTION_PREWARM = + "android.service.media.CameraPrewarmService.ACTION_PREWARM"; + + /** + * Message sent by the client indicating that the camera intent has been fired. + * @hide + */ + public static final int MSG_CAMERA_FIRED = 1; + + private final Handler mHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_CAMERA_FIRED: + mCameraIntentFired = true; + break; + default: + super.handleMessage(msg); + } + } + }; + private boolean mCameraIntentFired; + + @Override + public IBinder onBind(Intent intent) { + if (ACTION_PREWARM.equals(intent.getAction())) { + onPrewarm(); + return new Messenger(mHandler).getBinder(); + } else { + return null; + } + } + + @Override + public boolean onUnbind(Intent intent) { + if (ACTION_PREWARM.equals(intent.getAction())) { + onCooldown(mCameraIntentFired); + } + return false; + } + + /** + * Called when the camera should be prewarmed. + */ + public abstract void onPrewarm(); + + /** + * Called when prewarm phase is done, either because the camera launch intent has been fired + * at this point or prewarm is no longer needed. A client should close the camera + * immediately in the latter case. + * <p> + * In case the camera launch intent has been fired, there is no guarantee about the ordering + * of these two events. Cooldown might happen either before or after the activity has been + * created that handles the camera intent. + * + * @param cameraIntentFired Indicates whether the intent to launch the camera has been + * fired. + */ + public abstract void onCooldown(boolean cameraIntentFired); +} diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl index 894edac..8fe84e1 100644 --- a/core/java/android/service/voice/IVoiceInteractionSession.aidl +++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl @@ -16,8 +16,8 @@ package android.service.voice; -import android.app.AssistContent; -import android.app.AssistStructure; +import android.app.assist.AssistContent; +import android.app.assist.AssistStructure; import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 48ad5a8..33fef62 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -16,11 +16,11 @@ package android.service.voice; -import android.app.AssistContent; -import android.app.AssistStructure; import android.app.Dialog; import android.app.Instrumentation; import android.app.VoiceInteractor; +import android.app.assist.AssistContent; +import android.app.assist.AssistStructure; import android.content.ComponentCallbacks2; import android.content.Context; import android.content.Intent; @@ -386,7 +386,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } /** - * ASk the app to cancel this current request. + * ASk the app to cancelLocked this current request. */ public void cancel() { try { @@ -878,14 +878,34 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall show(null, 0); } - public void show(Bundle args, int showFlags) { + /** + * 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}. + * @param args Arbitrary arguments that will be propagated {@link #onShow}. + * @param flags Indicates additional optional behavior that should be performed. May + * be {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} + * to request that the system generate and deliver assist data on the current foreground + * app as part of showing the session UI. + */ + public void show(Bundle args, int flags) { + if (mToken == null) { + throw new IllegalStateException("Can't call before onCreate()"); + } try { - mSystemService.showSessionFromSession(mToken, null, 0); + mSystemService.showSessionFromSession(mToken, args, flags); } catch (RemoteException e) { } } + /** + * Hide the session's UI, if currently shown. Call this when you are done with your + * user interaction. + */ public void hide() { + if (mToken == null) { + throw new IllegalStateException("Can't call before onCreate()"); + } try { mSystemService.hideSessionFromSession(mToken); } catch (RemoteException e) { @@ -964,6 +984,9 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * {@link #startVoiceActivity}.</p> */ public void setKeepAwake(boolean keepAwake) { + if (mToken == null) { + throw new IllegalStateException("Can't call before onCreate()"); + } try { mSystemService.setKeepAwake(mToken, keepAwake); } catch (RemoteException e) { @@ -985,7 +1008,9 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } /** - * Finish the session. + * Finish the session. This completely destroys the session -- the next time it is shown, + * an entirely new one will be created. You do not normally call this function; instead, + * use {@link #hide} and allow the system to destroy your session if it needs its RAM. */ public void finish() { if (mToken == null) { @@ -1114,7 +1139,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * Called when the user presses the back button while focus is in the session UI. Note * that this will only happen if the session UI has requested input focus in its window; * otherwise, the back key will go to whatever window has focus and do whatever behavior - * it normally has there. + * it normally has there. The default implementation simply calls {@link #hide}. */ public void onBackPressed() { hide(); @@ -1123,7 +1148,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall /** * Sessions automatically watch for requests that all system UI be closed (such as when * the user presses HOME), which will appear here. The default implementation always - * calls {@link #finish}. + * calls {@link #hide}. */ public void onCloseSystemDialogs() { hide(); @@ -1287,7 +1312,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } /** - * Called when the {@link android.app.VoiceInteractor} has asked to cancel a {@link Request} + * Called when the {@link android.app.VoiceInteractor} has asked to cancelLocked a {@link Request} * that was previously delivered to {@link #onRequestConfirmation}, * {@link #onRequestPickOption}, {@link #onRequestCompleteVoice}, {@link #onRequestAbortVoice}, * or {@link #onRequestCommand}. diff --git a/core/java/android/text/Annotation.java b/core/java/android/text/Annotation.java index dbc290b..bb5d3ea 100644 --- a/core/java/android/text/Annotation.java +++ b/core/java/android/text/Annotation.java @@ -38,6 +38,11 @@ public class Annotation implements ParcelableSpan { } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.ANNOTATION; } @@ -46,6 +51,11 @@ public class Annotation implements ParcelableSpan { } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeString(mKey); dest.writeString(mValue); } diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java index e99a960..5b5cdd2 100644 --- a/core/java/android/text/DynamicLayout.java +++ b/core/java/android/text/DynamicLayout.java @@ -291,7 +291,7 @@ public class DynamicLayout extends Layout b.setText(text, where, where + after) .setPaint(getPaint()) .setWidth(getWidth()) - .setTextDir(getTextDirectionHeuristic()) + .setTextDirection(getTextDirectionHeuristic()) .setLineSpacing(getSpacingAdd(), getSpacingMultiplier()) .setEllipsizedWidth(mEllipsizedWidth) .setEllipsize(mEllipsizeAt) diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java index a99bdf5..67c36e3 100644 --- a/core/java/android/text/Hyphenator.java +++ b/core/java/android/text/Hyphenator.java @@ -16,6 +16,9 @@ package android.text; +import com.android.internal.annotations.GuardedBy; + +import android.annotation.Nullable; import android.util.Log; import java.io.File; @@ -36,6 +39,9 @@ public class Hyphenator { private static String TAG = "Hyphenator"; + private final static Object sLock = new Object(); + + @GuardedBy("sLock") static HashMap<Locale, Hyphenator> sMap = new HashMap<Locale, Hyphenator>(); private long mNativePtr; @@ -44,35 +50,94 @@ public class Hyphenator { mNativePtr = nativePtr; } - public static long get(Locale locale) { - Hyphenator result = sMap.get(locale); - return result == null ? 0 : result.mNativePtr; - } + public static long get(@Nullable Locale locale) { + synchronized (sLock) { + if (sMap.containsKey(locale)) { + Hyphenator result = sMap.get(locale); + return (result == null) ? 0 : result.mNativePtr; + } + + // TODO: Convert this a proper locale-fallback system - private static Hyphenator loadHyphenator(Locale locale) { - // TODO: find pattern dictionary (from system location) that best matches locale - if (Locale.US.equals(locale)) { - File f = new File(getSystemHyphenatorLocation(), "hyph-en-us.pat.txt"); - try { - RandomAccessFile rf = new RandomAccessFile(f, "r"); - byte[] buf = new byte[(int)rf.length()]; - rf.read(buf); - rf.close(); - String patternData = new String(buf); - long nativePtr = StaticLayout.nLoadHyphenator(patternData); - return new Hyphenator(nativePtr); - } catch (IOException e) { - Log.e(TAG, "error loading hyphenation " + f, e); + // Fall back to language-only, if available + Locale languageOnlyLocale = new Locale(locale.getLanguage()); + if (sMap.containsKey(languageOnlyLocale)) { + Hyphenator result = sMap.get(languageOnlyLocale); + sMap.put(locale, result); + return (result == null) ? 0 : result.mNativePtr; } + + // Fall back to script-only, if available + String script = locale.getScript(); + if (!script.equals("")) { + Locale scriptOnlyLocale = new Locale.Builder() + .setLanguage("und") + .setScript(script) + .build(); + if (sMap.containsKey(scriptOnlyLocale)) { + Hyphenator result = sMap.get(scriptOnlyLocale); + sMap.put(locale, result); + return (result == null) ? 0 : result.mNativePtr; + } + } + + sMap.put(locale, null); // To remember we found nothing. + } + return 0; + } + + private static Hyphenator loadHyphenator(String languageTag) { + String patternFilename = "hyph-"+languageTag.toLowerCase(Locale.US)+".pat.txt"; + File patternFile = new File(getSystemHyphenatorLocation(), patternFilename); + try { + RandomAccessFile rf = new RandomAccessFile(patternFile, "r"); + byte[] buf = new byte[(int)rf.length()]; + rf.read(buf); + rf.close(); + String patternData = new String(buf); + long nativePtr = StaticLayout.nLoadHyphenator(patternData); + return new Hyphenator(nativePtr); + } catch (IOException e) { + Log.e(TAG, "error loading hyphenation " + patternFile, e); } return null; } private static File getSystemHyphenatorLocation() { - // TODO: move to a sensible location under system return new File("/system/usr/hyphen-data"); } + // This array holds pairs of language tags that are used to prefill the map from locale to + // hyphenation data: The hyphenation data for the first field will be prefilled from the + // hyphenation data for the second field. + // + // The aliases that are computable by the get() method above are not included. + private static final String[][] LOCALE_FALLBACK_DATA = { + // English locales that fall back to en-US. The data is + // from CLDR. It's all English locales, minus the locales whose + // parent is en-001 (from supplementalData.xml, under <parentLocales>). + // TODO: Figure out how to get this from ICU. + {"en-AS", "en-US"}, // English (American Samoa) + {"en-GU", "en-US"}, // English (Guam) + {"en-MH", "en-US"}, // English (Marshall Islands) + {"en-MP", "en-US"}, // English (Northern Mariana Islands) + {"en-PR", "en-US"}, // English (Puerto Rico) + {"en-UM", "en-US"}, // English (United States Minor Outlying Islands) + {"en-VI", "en-US"}, // English (Virgin Islands) + + // Norwegian is very probably Norwegian Bokmål. + {"no", "nb"}, + + // Fall back to Ethiopic script for languages likely to be written in Ethiopic. + // Data is from CLDR's likelySubtags.xml. + // TODO: Convert this to a mechanism using ICU4J's ULocale#addLikelySubtags(). + {"am", "und-Ethi"}, // Amharic + {"byn", "und-Ethi"}, // Blin + {"gez", "und-Ethi"}, // Geʻez + {"ti", "und-Ethi"}, // Tigrinya + {"wal", "und-Ethi"}, // Wolaytta + }; + /** * Load hyphenation patterns at initialization time. We want to have patterns * for all locales loaded and ready to use so we don't have to do any file IO @@ -81,7 +146,22 @@ public class Hyphenator { * @hide */ public static void init() { - Locale l = Locale.US; - sMap.put(l, loadHyphenator(l)); + sMap.put(null, null); + + // TODO: replace this with a discovery-based method that looks into /system/usr/hyphen-data + String[] availableLanguages = {"en-US", "eu", "hu", "hy", "nb", "nn", "sa", "und-Ethi"}; + for (int i = 0; i < availableLanguages.length; i++) { + String languageTag = availableLanguages[i]; + Hyphenator h = loadHyphenator(languageTag); + if (h != null) { + sMap.put(Locale.forLanguageTag(languageTag), h); + } + } + + for (int i = 0; i < LOCALE_FALLBACK_DATA.length; i++) { + String language = LOCALE_FALLBACK_DATA[i][0]; + String fallback = LOCALE_FALLBACK_DATA[i][1]; + sMap.put(Locale.forLanguageTag(language), sMap.get(Locale.forLanguageTag(fallback))); + } } } diff --git a/core/java/android/text/ParcelableSpan.java b/core/java/android/text/ParcelableSpan.java index 224511a..d7c1a4b 100644 --- a/core/java/android/text/ParcelableSpan.java +++ b/core/java/android/text/ParcelableSpan.java @@ -16,6 +16,7 @@ package android.text; +import android.os.Parcel; import android.os.Parcelable; /** @@ -27,5 +28,21 @@ public interface ParcelableSpan extends Parcelable { /** * Return a special type identifier for this span class. */ - public abstract int getSpanTypeId(); + int getSpanTypeId(); + + /** + * Internal implementation of {@link #getSpanTypeId()} that is not meant to + * be overridden outside of the framework. + * + * @hide + */ + int getSpanTypeIdInternal(); + + /** + * Internal implementation of {@link Parcelable#writeToParcel(Parcel, int)} + * that is not meant to be overridden outside of the framework. + * + * @hide + */ + void writeToParcelInternal(Parcel dest, int flags); } diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index d6d046b..464710b 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -184,7 +184,7 @@ public class StaticLayout extends Layout { * @param textDir text direction heuristic for resolving BiDi behavior. * @return this builder, useful for chaining */ - public Builder setTextDir(TextDirectionHeuristic textDir) { + public Builder setTextDirection(TextDirectionHeuristic textDir) { mTextDir = textDir; return this; } @@ -473,7 +473,7 @@ public class StaticLayout extends Layout { Builder b = Builder.obtain(source, bufstart, bufend, paint, outerwidth) .setAlignment(align) - .setTextDir(textDir) + .setTextDirection(textDir) .setLineSpacing(spacingadd, spacingmult) .setIncludePad(includepad) .setEllipsizedWidth(ellipsizedWidth) diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index 676986d..6c4d8fd 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -622,8 +622,7 @@ public class TextUtils { * Flatten a CharSequence and whatever styles can be copied across processes * into the parcel. */ - public static void writeToParcel(CharSequence cs, Parcel p, - int parcelableFlags) { + public static void writeToParcel(CharSequence cs, Parcel p, int parcelableFlags) { if (cs instanceof Spanned) { p.writeInt(0); p.writeString(cs.toString()); @@ -645,15 +644,15 @@ public class TextUtils { } if (prop instanceof ParcelableSpan) { - ParcelableSpan ps = (ParcelableSpan)prop; - int spanTypeId = ps.getSpanTypeId(); + final ParcelableSpan ps = (ParcelableSpan) prop; + final int spanTypeId = ps.getSpanTypeIdInternal(); if (spanTypeId < FIRST_SPAN || spanTypeId > LAST_SPAN) { - Log.e(TAG, "external class \"" + ps.getClass().getSimpleName() + Log.e(TAG, "External class \"" + ps.getClass().getSimpleName() + "\" is attempting to use the frameworks-only ParcelableSpan" + " interface"); } else { p.writeInt(spanTypeId); - ps.writeToParcel(p, parcelableFlags); + ps.writeToParcelInternal(p, parcelableFlags); writeWhere(p, sp, o); } } diff --git a/core/java/android/text/style/AbsoluteSizeSpan.java b/core/java/android/text/style/AbsoluteSizeSpan.java index 1214040..908ef55 100644 --- a/core/java/android/text/style/AbsoluteSizeSpan.java +++ b/core/java/android/text/style/AbsoluteSizeSpan.java @@ -49,6 +49,11 @@ public class AbsoluteSizeSpan extends MetricAffectingSpan implements ParcelableS } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.ABSOLUTE_SIZE_SPAN; } @@ -57,6 +62,11 @@ public class AbsoluteSizeSpan extends MetricAffectingSpan implements ParcelableS } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeInt(mSize); dest.writeInt(mDip ? 1 : 0); } diff --git a/core/java/android/text/style/AlignmentSpan.java b/core/java/android/text/style/AlignmentSpan.java index b8a37da..6158309 100644 --- a/core/java/android/text/style/AlignmentSpan.java +++ b/core/java/android/text/style/AlignmentSpan.java @@ -22,10 +22,9 @@ import android.text.ParcelableSpan; import android.text.TextUtils; public interface AlignmentSpan extends ParagraphStyle { - public Layout.Alignment getAlignment(); + Layout.Alignment getAlignment(); - public static class Standard - implements AlignmentSpan, ParcelableSpan { + class Standard implements AlignmentSpan, ParcelableSpan { public Standard(Layout.Alignment align) { mAlignment = align; } @@ -35,6 +34,11 @@ public interface AlignmentSpan extends ParagraphStyle { } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.ALIGNMENT_SPAN; } @@ -43,6 +47,11 @@ public interface AlignmentSpan extends ParagraphStyle { } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeString(mAlignment.name()); } diff --git a/core/java/android/text/style/BackgroundColorSpan.java b/core/java/android/text/style/BackgroundColorSpan.java index cda8015..de05f50 100644 --- a/core/java/android/text/style/BackgroundColorSpan.java +++ b/core/java/android/text/style/BackgroundColorSpan.java @@ -35,6 +35,11 @@ public class BackgroundColorSpan extends CharacterStyle } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.BACKGROUND_COLOR_SPAN; } @@ -43,6 +48,11 @@ public class BackgroundColorSpan extends CharacterStyle } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeInt(mColor); } diff --git a/core/java/android/text/style/BulletSpan.java b/core/java/android/text/style/BulletSpan.java index 3f86b08..7408415 100644 --- a/core/java/android/text/style/BulletSpan.java +++ b/core/java/android/text/style/BulletSpan.java @@ -60,6 +60,11 @@ public class BulletSpan implements LeadingMarginSpan, ParcelableSpan { } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.BULLET_SPAN; } @@ -68,6 +73,11 @@ public class BulletSpan implements LeadingMarginSpan, ParcelableSpan { } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeInt(mGapWidth); dest.writeInt(mWantColor ? 1 : 0); dest.writeInt(mColor); diff --git a/core/java/android/text/style/EasyEditSpan.java b/core/java/android/text/style/EasyEditSpan.java index 03b4f60..7af1c2c 100644 --- a/core/java/android/text/style/EasyEditSpan.java +++ b/core/java/android/text/style/EasyEditSpan.java @@ -91,12 +91,22 @@ public class EasyEditSpan implements ParcelableSpan { @Override public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeParcelable(mPendingIntent, 0); dest.writeByte((byte) (mDeleteEnabled ? 1 : 0)); } @Override public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.EASY_EDIT_SPAN; } diff --git a/core/java/android/text/style/ForegroundColorSpan.java b/core/java/android/text/style/ForegroundColorSpan.java index f167aab..2bc6d54 100644 --- a/core/java/android/text/style/ForegroundColorSpan.java +++ b/core/java/android/text/style/ForegroundColorSpan.java @@ -36,14 +36,24 @@ public class ForegroundColorSpan extends CharacterStyle } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.FOREGROUND_COLOR_SPAN; } - + public int describeContents() { return 0; } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeInt(mColor); } diff --git a/core/java/android/text/style/LeadingMarginSpan.java b/core/java/android/text/style/LeadingMarginSpan.java index 96a7cd9..339d885 100644 --- a/core/java/android/text/style/LeadingMarginSpan.java +++ b/core/java/android/text/style/LeadingMarginSpan.java @@ -125,6 +125,11 @@ extends ParagraphStyle } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.LEADING_MARGIN_SPAN; } @@ -133,6 +138,11 @@ extends ParagraphStyle } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeInt(mFirst); dest.writeInt(mRest); } diff --git a/core/java/android/text/style/LocaleSpan.java b/core/java/android/text/style/LocaleSpan.java index a12c42f..d286231 100644 --- a/core/java/android/text/style/LocaleSpan.java +++ b/core/java/android/text/style/LocaleSpan.java @@ -44,6 +44,11 @@ public class LocaleSpan extends MetricAffectingSpan implements ParcelableSpan { @Override public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.LOCALE_SPAN; } @@ -54,6 +59,11 @@ public class LocaleSpan extends MetricAffectingSpan implements ParcelableSpan { @Override public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeString(mLocale.getLanguage()); dest.writeString(mLocale.getCountry()); dest.writeString(mLocale.getVariant()); diff --git a/core/java/android/text/style/QuoteSpan.java b/core/java/android/text/style/QuoteSpan.java index 17748ca..0b0a82c 100644 --- a/core/java/android/text/style/QuoteSpan.java +++ b/core/java/android/text/style/QuoteSpan.java @@ -45,6 +45,11 @@ public class QuoteSpan implements LeadingMarginSpan, ParcelableSpan { } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.QUOTE_SPAN; } @@ -53,6 +58,11 @@ public class QuoteSpan implements LeadingMarginSpan, ParcelableSpan { } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeInt(mColor); } diff --git a/core/java/android/text/style/RelativeSizeSpan.java b/core/java/android/text/style/RelativeSizeSpan.java index 632dbd4..95f048a 100644 --- a/core/java/android/text/style/RelativeSizeSpan.java +++ b/core/java/android/text/style/RelativeSizeSpan.java @@ -34,6 +34,11 @@ public class RelativeSizeSpan extends MetricAffectingSpan implements ParcelableS } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.RELATIVE_SIZE_SPAN; } @@ -42,6 +47,11 @@ public class RelativeSizeSpan extends MetricAffectingSpan implements ParcelableS } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeFloat(mProportion); } diff --git a/core/java/android/text/style/ScaleXSpan.java b/core/java/android/text/style/ScaleXSpan.java index a22a5a1..d085018 100644 --- a/core/java/android/text/style/ScaleXSpan.java +++ b/core/java/android/text/style/ScaleXSpan.java @@ -34,6 +34,11 @@ public class ScaleXSpan extends MetricAffectingSpan implements ParcelableSpan { } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.SCALE_X_SPAN; } @@ -42,6 +47,11 @@ public class ScaleXSpan extends MetricAffectingSpan implements ParcelableSpan { } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeFloat(mProportion); } diff --git a/core/java/android/text/style/SpellCheckSpan.java b/core/java/android/text/style/SpellCheckSpan.java index 0d8a103..10275c2 100644 --- a/core/java/android/text/style/SpellCheckSpan.java +++ b/core/java/android/text/style/SpellCheckSpan.java @@ -54,11 +54,21 @@ public class SpellCheckSpan implements ParcelableSpan { @Override public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeInt(mSpellCheckInProgress ? 1 : 0); } @Override public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.SPELL_CHECK_SPAN; } } diff --git a/core/java/android/text/style/StrikethroughSpan.java b/core/java/android/text/style/StrikethroughSpan.java index 303e415..1389704 100644 --- a/core/java/android/text/style/StrikethroughSpan.java +++ b/core/java/android/text/style/StrikethroughSpan.java @@ -30,6 +30,11 @@ public class StrikethroughSpan extends CharacterStyle } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.STRIKETHROUGH_SPAN; } @@ -38,6 +43,11 @@ public class StrikethroughSpan extends CharacterStyle } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { } @Override diff --git a/core/java/android/text/style/StyleSpan.java b/core/java/android/text/style/StyleSpan.java index b08f70e..f900db5 100644 --- a/core/java/android/text/style/StyleSpan.java +++ b/core/java/android/text/style/StyleSpan.java @@ -50,6 +50,11 @@ public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan { } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.STYLE_SPAN; } @@ -58,6 +63,11 @@ public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan { } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeInt(mStyle); } diff --git a/core/java/android/text/style/SubscriptSpan.java b/core/java/android/text/style/SubscriptSpan.java index de1d8b2..f1b0d38 100644 --- a/core/java/android/text/style/SubscriptSpan.java +++ b/core/java/android/text/style/SubscriptSpan.java @@ -29,6 +29,11 @@ public class SubscriptSpan extends MetricAffectingSpan implements ParcelableSpan } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.SUBSCRIPT_SPAN; } @@ -37,6 +42,11 @@ public class SubscriptSpan extends MetricAffectingSpan implements ParcelableSpan } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { } @Override diff --git a/core/java/android/text/style/SuggestionRangeSpan.java b/core/java/android/text/style/SuggestionRangeSpan.java index 2dbfc72..c1943d5 100644 --- a/core/java/android/text/style/SuggestionRangeSpan.java +++ b/core/java/android/text/style/SuggestionRangeSpan.java @@ -46,11 +46,21 @@ public class SuggestionRangeSpan extends CharacterStyle implements ParcelableSpa @Override public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeInt(mBackgroundColor); } @Override public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.SUGGESTION_RANGE_SPAN; } diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java index 8b40953..6b449f9 100644 --- a/core/java/android/text/style/SuggestionSpan.java +++ b/core/java/android/text/style/SuggestionSpan.java @@ -248,6 +248,11 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { @Override public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeStringArray(mSuggestions); dest.writeInt(mFlags); dest.writeString(mLocaleString); @@ -264,6 +269,11 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { @Override public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.SUGGESTION_SPAN; } diff --git a/core/java/android/text/style/SuperscriptSpan.java b/core/java/android/text/style/SuperscriptSpan.java index 285fe84..abcf688 100644 --- a/core/java/android/text/style/SuperscriptSpan.java +++ b/core/java/android/text/style/SuperscriptSpan.java @@ -29,6 +29,11 @@ public class SuperscriptSpan extends MetricAffectingSpan implements ParcelableSp } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.SUPERSCRIPT_SPAN; } @@ -37,6 +42,11 @@ public class SuperscriptSpan extends MetricAffectingSpan implements ParcelableSp } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { } @Override diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java index ecbf4bc..abbd793 100644 --- a/core/java/android/text/style/TextAppearanceSpan.java +++ b/core/java/android/text/style/TextAppearanceSpan.java @@ -136,6 +136,11 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.TEXT_APPEARANCE_SPAN; } @@ -144,6 +149,11 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeString(mTypeface); dest.writeInt(mStyle); dest.writeInt(mTextSize); diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java index 342a183..c40f11f 100644 --- a/core/java/android/text/style/TtsSpan.java +++ b/core/java/android/text/style/TtsSpan.java @@ -495,12 +495,22 @@ public class TtsSpan implements ParcelableSpan { @Override public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeString(mType); dest.writePersistableBundle(mArgs); } @Override public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.TTS_SPAN; } diff --git a/core/java/android/text/style/TypefaceSpan.java b/core/java/android/text/style/TypefaceSpan.java index f194060..aa622d8 100644 --- a/core/java/android/text/style/TypefaceSpan.java +++ b/core/java/android/text/style/TypefaceSpan.java @@ -42,6 +42,11 @@ public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.TYPEFACE_SPAN; } @@ -50,6 +55,11 @@ public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeString(mFamily); } diff --git a/core/java/android/text/style/URLSpan.java b/core/java/android/text/style/URLSpan.java index 0669b6f..58239ef 100644 --- a/core/java/android/text/style/URLSpan.java +++ b/core/java/android/text/style/URLSpan.java @@ -40,6 +40,11 @@ public class URLSpan extends ClickableSpan implements ParcelableSpan { } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.URL_SPAN; } @@ -48,6 +53,11 @@ public class URLSpan extends ClickableSpan implements ParcelableSpan { } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { dest.writeString(mURL); } diff --git a/core/java/android/text/style/UnderlineSpan.java b/core/java/android/text/style/UnderlineSpan.java index 80b2427..9024dcd 100644 --- a/core/java/android/text/style/UnderlineSpan.java +++ b/core/java/android/text/style/UnderlineSpan.java @@ -30,6 +30,11 @@ public class UnderlineSpan extends CharacterStyle } public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + public int getSpanTypeIdInternal() { return TextUtils.UNDERLINE_SPAN; } @@ -38,6 +43,11 @@ public class UnderlineSpan extends CharacterStyle } public void writeToParcel(Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + public void writeToParcelInternal(Parcel dest, int flags) { } @Override diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index d0e5b9e..a36e66c 100644 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -79,6 +79,14 @@ public class DisplayMetrics { * This is not a density that applications should target, instead relying * on the system to scale their {@link #DENSITY_XXHIGH} assets for them. */ + public static final int DENSITY_360 = 360; + + /** + * Intermediate density for screens that sit somewhere between + * {@link #DENSITY_XHIGH} (320 dpi) and {@link #DENSITY_XXHIGH} (480 dpi). + * This is not a density that applications should target, instead relying + * on the system to scale their {@link #DENSITY_XXHIGH} assets for them. + */ public static final int DENSITY_400 = 400; /** diff --git a/core/java/android/util/StateSet.java b/core/java/android/util/StateSet.java index 83dfc47..c2a6a7a 100644 --- a/core/java/android/util/StateSet.java +++ b/core/java/android/util/StateSet.java @@ -119,7 +119,14 @@ public class StateSet { /** @hide */ public StateSet() {} + /** + * A state specification that will be matched by all StateSets. + */ public static final int[] WILD_CARD = new int[0]; + + /** + * A state set that does not contain any valid states. + */ public static final int[] NOTHING = new int[] { 0 }; /** diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index 6e2d110..664c02a 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -19,6 +19,7 @@ package android.view; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; +import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -158,7 +159,9 @@ final class AccessibilityInteractionController { try { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; applyAppScaleAndMagnificationSpecIfNeeded(infos, spec); - if (spec != null) { + // Recycle if called from another process. Specs are cached in the + // system process and obtained from a pool when read from parcel. + if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) { spec.recycle(); } adjustIsVisibleToUserIfNeeded(infos, interactiveRegion); @@ -167,6 +170,12 @@ final class AccessibilityInteractionController { } catch (RemoteException re) { /* ignore - the other side will time out */ } + + // Recycle if called from the same process. Regions are obtained in + // the system process and instantiated when read from parcel. + if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) { + interactiveRegion.recycle(); + } } } @@ -244,7 +253,9 @@ final class AccessibilityInteractionController { try { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; applyAppScaleAndMagnificationSpecIfNeeded(infos, spec); - if (spec != null) { + // Recycle if called from another process. Specs are cached in the + // system process and obtained from a pool when read from parcel. + if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) { spec.recycle(); } adjustIsVisibleToUserIfNeeded(infos, interactiveRegion); @@ -252,6 +263,12 @@ final class AccessibilityInteractionController { } catch (RemoteException re) { /* ignore - the other side will time out */ } + + // Recycle if called from the same process. Regions are obtained in + // the system process and instantiated when read from parcel. + if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) { + interactiveRegion.recycle(); + } } } @@ -354,7 +371,9 @@ final class AccessibilityInteractionController { try { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; applyAppScaleAndMagnificationSpecIfNeeded(infos, spec); - if (spec != null) { + // Recycle if called from another process. Specs are cached in the + // system process and obtained from a pool when read from parcel. + if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) { spec.recycle(); } adjustIsVisibleToUserIfNeeded(infos, interactiveRegion); @@ -362,6 +381,12 @@ final class AccessibilityInteractionController { } catch (RemoteException re) { /* ignore - the other side will time out */ } + + // Recycle if called from the same process. Regions are obtained in + // the system process and instantiated when read from parcel. + if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) { + interactiveRegion.recycle(); + } } } @@ -468,7 +493,9 @@ final class AccessibilityInteractionController { try { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; applyAppScaleAndMagnificationSpecIfNeeded(focused, spec); - if (spec != null) { + // Recycle if called from another process. Specs are cached in the + // system process and obtained from a pool when read from parcel. + if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) { spec.recycle(); } adjustIsVisibleToUserIfNeeded(focused, interactiveRegion); @@ -476,6 +503,12 @@ final class AccessibilityInteractionController { } catch (RemoteException re) { /* ignore - the other side will time out */ } + + // Recycle if called from the same process. Regions are obtained in + // the system process and instantiated when read from parcel. + if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) { + interactiveRegion.recycle(); + } } } @@ -545,7 +578,9 @@ final class AccessibilityInteractionController { try { mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0; applyAppScaleAndMagnificationSpecIfNeeded(next, spec); - if (spec != null) { + // Recycle if called from another process. Specs are cached in the + // system process and obtained from a pool when read from parcel. + if (spec != null && android.os.Process.myPid() != Binder.getCallingPid()) { spec.recycle(); } adjustIsVisibleToUserIfNeeded(next, interactiveRegion); @@ -553,6 +588,12 @@ final class AccessibilityInteractionController { } catch (RemoteException re) { /* ignore - the other side will time out */ } + + // Recycle if called from the same process. Regions are obtained in + // the system process and instantiated when read from parcel. + if (interactiveRegion != null && android.os.Process.myPid() == Binder.getCallingPid()) { + interactiveRegion.recycle(); + } } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index cfd504d..126540f 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1661,8 +1661,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** {@hide} */ static final int PFLAG_SKIP_DRAW = 0x00000080; /** {@hide} */ - static final int PFLAG_ONLY_DRAWS_BACKGROUND = 0x00000100; - /** {@hide} */ static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; /** {@hide} */ static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; @@ -7368,7 +7366,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ public void getOutsets(Rect outOutsetRect) { - outOutsetRect.set(mAttachInfo.mOutsets); + if (mAttachInfo != null) { + outOutsetRect.set(mAttachInfo.mOutsets); + } else { + outOutsetRect.setEmpty(); + } } /** @@ -10619,9 +10621,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if ((changed & DRAW_MASK) != 0) { if ((mViewFlags & WILL_NOT_DRAW) != 0) { - if (mBackground != null) { + if (mBackground != null + || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { mPrivateFlags &= ~PFLAG_SKIP_DRAW; - mPrivateFlags |= PFLAG_ONLY_DRAWS_BACKGROUND; } else { mPrivateFlags |= PFLAG_SKIP_DRAW; } @@ -17113,6 +17115,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator * attached to this view. */ + @CallSuper public void jumpDrawablesToCurrentState() { if (mBackground != null) { mBackground.jumpToCurrentState(); @@ -17260,20 +17263,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { mPrivateFlags &= ~PFLAG_SKIP_DRAW; - mPrivateFlags |= PFLAG_ONLY_DRAWS_BACKGROUND; requestLayout = true; } } else { /* Remove the background */ mBackground = null; - - if ((mPrivateFlags & PFLAG_ONLY_DRAWS_BACKGROUND) != 0) { - /* - * This view ONLY drew the background before and we're removing - * the background, so now it won't draw anything - * (hence we SKIP_DRAW) - */ - mPrivateFlags &= ~PFLAG_ONLY_DRAWS_BACKGROUND; + if ((mViewFlags & WILL_NOT_DRAW) != 0 + && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { mPrivateFlags |= PFLAG_SKIP_DRAW; } @@ -17447,13 +17443,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mForegroundInfo.mDrawable = foreground; mForegroundInfo.mBoundsChanged = true; if (foreground != null) { - setWillNotDraw(false); + if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { + mPrivateFlags &= ~PFLAG_SKIP_DRAW; + } foreground.setCallback(this); foreground.setLayoutDirection(getLayoutDirection()); if (foreground.isStateful()) { foreground.setState(getDrawableState()); } applyForegroundTint(); + } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null) { + mPrivateFlags |= PFLAG_SKIP_DRAW; } requestLayout(); invalidate(); @@ -17565,13 +17565,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see Drawable#setTintMode(PorterDuff.Mode) */ public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { - if (mBackgroundTint == null) { - mBackgroundTint = new TintInfo(); + if (mForegroundInfo == null) { + mForegroundInfo = new ForegroundInfo(); } - mBackgroundTint.mTintMode = tintMode; - mBackgroundTint.mHasTintMode = true; + if (mForegroundInfo.mTintInfo == null) { + mForegroundInfo.mTintInfo = new TintInfo(); + } + mForegroundInfo.mTintInfo.mTintMode = tintMode; + mForegroundInfo.mTintInfo.mHasTintMode = true; - applyBackgroundTint(); + applyForegroundTint(); } /** @@ -17581,7 +17584,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return the blending mode used to apply the tint to the foreground * drawable * @attr ref android.R.styleable#View_foregroundTintMode - * @see #setBackgroundTintMode(PorterDuff.Mode) + * @see #setForegroundTintMode(PorterDuff.Mode) */ @Nullable public PorterDuff.Mode getForegroundTintMode() { @@ -18291,7 +18294,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (accessibilityId < 0) { return null; } - return findViewByAccessibilityIdTraversal(accessibilityId); + View view = findViewByAccessibilityIdTraversal(accessibilityId); + if (view != null) { + return view.includeForAccessibility() ? view : null; + } + return null; } /** @@ -19181,16 +19188,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, getLocationInWindow(location); region.op(location[0], location[1], location[0] + mRight - mLeft, location[1] + mBottom - mTop, Region.Op.DIFFERENCE); - } else if ((pflags & PFLAG_ONLY_DRAWS_BACKGROUND) != 0 && mBackground != null && - mBackground.getOpacity() != PixelFormat.TRANSPARENT) { - // The ONLY_DRAWS_BACKGROUND flag IS set and the background drawable - // exists, so we remove the background drawable's non-transparent - // parts from this transparent region. - applyDrawableToTransparentRegion(mBackground, region); - } - final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; - if (foreground != null) { - applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); + } else { + if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { + // The SKIP_DRAW flag IS set and the background drawable exists, we remove + // the background drawable's non-transparent parts from this transparent region. + applyDrawableToTransparentRegion(mBackground, region); + } + if (mForegroundInfo != null && mForegroundInfo.mDrawable != null + && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { + // Similarly, we remove the foreground drawable's non-transparent parts. + applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); + } } } return true; diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index e015c04..dd32f85 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -1173,6 +1173,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (foundView != null) { return foundView; } + + if (getAccessibilityNodeProvider() != null) { + return null; + } + final int childrenCount = mChildrenCount; final View[] children = mChildren; for (int i = 0; i < childrenCount; i++) { @@ -1182,6 +1187,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return foundView; } } + return null; } diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java index 886547a..e525474 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -18,7 +18,6 @@ package android.view; import android.graphics.Rect; import android.os.Bundle; -import android.text.TextPaint; /** * Container for storing additional per-view data generated by {@link View#onProvideStructure diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index 9e0719d..997e7e8 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -251,7 +251,7 @@ public final class WindowInsets { * @return true if any inset values are nonzero */ public boolean hasInsets() { - return hasSystemWindowInsets() || hasWindowDecorInsets(); + return hasSystemWindowInsets() || hasWindowDecorInsets() || hasStableInsets(); } /** diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index f0c86e5..45bc1df 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -309,6 +309,7 @@ public interface WindowManager extends ViewManager { * Window type: a above sub-panel on top of an application window and it's * sub-panel windows. These windows are displayed on top of their attached window * and any {@link #TYPE_APPLICATION_SUB_PANEL} panels. + * @hide */ public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5; diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index f7b6405..ca5f5ad 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -1058,6 +1058,13 @@ public interface WindowManagerPolicy { public boolean isKeyguardSecure(); /** + * Return whether the keyguard is on. + * + * @return true if in keyguard is on. + */ + public boolean isKeyguardShowingOrOccluded(); + + /** * inKeyguardRestrictedKeyInputMode * * if keyguard screen is showing or in restricted key input mode (i.e. in diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 5537b3e..053b35c 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -24,6 +24,7 @@ import com.android.internal.view.IInputMethodManager; import com.android.internal.view.IInputMethodSession; import com.android.internal.view.InputBindResult; +import android.annotation.RequiresPermission; import android.content.Context; import android.graphics.Matrix; import android.graphics.Rect; @@ -60,6 +61,8 @@ import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import static android.Manifest.permission.WRITE_SECURE_SETTINGS; + /** * Central system API to the overall input method framework (IMF) architecture, * which arbitrates interaction between applications and the current input method. @@ -1976,6 +1979,7 @@ public final class InputMethodManager { * @return true if the current subtype was successfully switched. When the specified subtype is * null, this method returns false. */ + @RequiresPermission(WRITE_SECURE_SETTINGS) public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) { synchronized (mH) { try { diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java index c2f3777..4ee155c 100644 --- a/core/java/android/view/inputmethod/InputMethodSubtype.java +++ b/core/java/android/view/inputmethod/InputMethodSubtype.java @@ -16,6 +16,7 @@ package android.view.inputmethod; +import android.annotation.Nullable; import android.content.Context; import android.content.pm.ApplicationInfo; import android.os.Parcel; @@ -323,6 +324,19 @@ public final class InputMethodSubtype implements Parcelable { } /** + * @return The normalized {@link Locale} object of the subtype. The returned locale may or may + * not equal to "locale" string parameter passed to the constructor. + * + * <p>TODO: Consider to make this a public API.</p> + * @hide + */ + @Nullable + public Locale getLocaleObject() { + // TODO: Move the following method from InputMethodUtils to InputMethodSubtype. + return InputMethodUtils.constructLocaleFromString(mSubtypeLocale); + } + + /** * @return The mode of the subtype. */ public String getMode() { @@ -381,7 +395,7 @@ public final class InputMethodSubtype implements Parcelable { */ public CharSequence getDisplayName( Context context, String packageName, ApplicationInfo appInfo) { - final Locale locale = InputMethodUtils.constructLocaleFromString(mSubtypeLocale); + final Locale locale = getLocaleObject(); final String localeStr = locale != null ? locale.getDisplayName() : mSubtypeLocale; if (mSubtypeNameResId == 0) { return localeStr; diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java index 84f395a..195a335 100644 --- a/core/java/android/view/textservice/SpellCheckerSession.java +++ b/core/java/android/view/textservice/SpellCheckerSession.java @@ -98,11 +98,11 @@ public class SpellCheckerSession { private final InternalListener mInternalListener; private final ITextServicesManager mTextServicesManager; private final SpellCheckerInfo mSpellCheckerInfo; + private final SpellCheckerSessionListener mSpellCheckerSessionListener; private final SpellCheckerSessionListenerImpl mSpellCheckerSessionListenerImpl; private final SpellCheckerSubtype mSubtype; private boolean mIsUsed; - private SpellCheckerSessionListener mSpellCheckerSessionListener; /** Handler that will execute the main tasks */ private final Handler mHandler = new Handler() { diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index a3332fa..a0d1930 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -2345,8 +2345,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } - // Scrap view implies temporary detachment. isScrap[0] = true; + + // Finish the temporary detach started in addScrapView(). + transientView.dispatchFinishTemporaryDetach(); return transientView; } @@ -2359,6 +2361,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } else { isScrap[0] = true; + // Finish the temporary detach started in addScrapView(). child.dispatchFinishTemporaryDetach(); } } diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java index ae94a10..027f6d6 100644 --- a/core/java/android/widget/ArrayAdapter.java +++ b/core/java/android/widget/ArrayAdapter.java @@ -50,14 +50,7 @@ import java.util.List; * or to have some of data besides toString() results fill the views, * override {@link #getView(int, View, ViewGroup)} to return the type of view you want. */ -public class ArrayAdapter<T> extends BaseAdapter implements Filterable, - Spinner.ThemedSpinnerAdapter { - /** - * Contains the list of objects that represent the data of this ArrayAdapter. - * The content of this list is referred to as "the array" in the documentation. - */ - private List<T> mObjects; - +public class ArrayAdapter<T> extends BaseAdapter implements Filterable, ThemedSpinnerAdapter { /** * Lock used to modify the content of {@link #mObjects}. Any write operation * performed on the array should be synchronized on this lock. This lock is also @@ -66,6 +59,14 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable, */ private final Object mLock = new Object(); + private final LayoutInflater mInflater; + + /** + * Contains the list of objects that represent the data of this ArrayAdapter. + * The content of this list is referred to as "the array" in the documentation. + */ + private List<T> mObjects; + /** * The resource indicating what views to inflate to display the content of this * array adapter. @@ -98,8 +99,6 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable, private ArrayList<T> mOriginalValues; private ArrayFilter mFilter; - private LayoutInflater mInflater; - /** Layout inflater used for {@link #getDropDownView(int, View, ViewGroup)}. */ private LayoutInflater mDropDownInflater; @@ -443,9 +442,6 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable, return mDropDownInflater == null ? null : mDropDownInflater.getContext().getTheme(); } - /** - * {@inheritDoc} - */ @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { final LayoutInflater inflater = mDropDownInflater == null ? mInflater : mDropDownInflater; diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java index d8ce60c..9fb98db 100644 --- a/core/java/android/widget/CursorAdapter.java +++ b/core/java/android/widget/CursorAdapter.java @@ -38,7 +38,7 @@ import android.view.ViewGroup; * columns. */ public abstract class CursorAdapter extends BaseAdapter implements Filterable, - CursorFilter.CursorFilterClient, Spinner.ThemedSpinnerAdapter { + CursorFilter.CursorFilterClient, ThemedSpinnerAdapter { /** * This field should be made private, so it is hidden from the SDK. * {@hide} diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java index d38a225..7e542c9 100755 --- a/core/java/android/widget/DatePickerCalendarDelegate.java +++ b/core/java/android/widget/DatePickerCalendarDelegate.java @@ -115,7 +115,8 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate { R.styleable.DatePicker_internalLayout, R.layout.date_picker_material); // Set up and attach container. - mContainer = (ViewGroup) inflater.inflate(layoutResourceId, mDelegator); + mContainer = (ViewGroup) inflater.inflate(layoutResourceId, mDelegator, false); + mDelegator.addView(mContainer); // Set up header views. final ViewGroup header = (ViewGroup) mContainer.findViewById(R.id.date_picker_header); @@ -471,7 +472,11 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate { @Override public void setEnabled(boolean enabled) { - mContainer.setEnabled(false); + mContainer.setEnabled(enabled); + mDayPickerView.setEnabled(enabled); + mYearPickerView.setEnabled(enabled); + mHeaderYear.setEnabled(enabled); + mHeaderMonthDay.setEnabled(enabled); } @Override @@ -481,8 +486,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate { @Override public CalendarView getCalendarView() { - throw new UnsupportedOperationException( - "CalendarView does not exists for the new DatePicker"); + throw new UnsupportedOperationException("Not supported by calendar-mode DatePicker"); } @Override diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 0cac529..56f9b5c 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -1004,14 +1004,14 @@ public class Editor { stopSelectionActionMode(); } else { stopSelectionActionMode(); - startSelectionActionModeWithSelectionAndStartDrag(); + selectCurrentWordAndStartDrag(); } handled = true; } // Start a new selection if (!handled) { - handled = startSelectionActionModeWithSelectionAndStartDrag(); + handled = selectCurrentWordAndStartDrag(); } return handled; @@ -1724,22 +1724,9 @@ public class Editor { } /** - * Starts a Selection Action Mode with the current selection and enters drag mode. This should - * be used whenever the mode is started from a touch event. - * - * @return true if the selection mode was actually started. - */ - private boolean startSelectionActionModeWithSelectionAndStartDrag() { - boolean selectionStarted = startSelectionActionModeWithSelectionInternal(); - if (selectionStarted) { - getSelectionController().enterDrag(); - } - return selectionStarted; - } - - /** * Starts a Selection Action Mode with the current selection and ensures the selection handles - * are shown. This should be used when the mode is started from a non-touch event. + * are shown if there is a selection, otherwise the insertion handle is shown. This should be + * used when the mode is started from a non-touch event. * * @return true if the selection mode was actually started. */ @@ -1747,38 +1734,65 @@ public class Editor { boolean selectionStarted = startSelectionActionModeWithSelectionInternal(); if (selectionStarted) { getSelectionController().show(); + } else if (getInsertionController() != null) { + getInsertionController().show(); } return selectionStarted; } - private boolean startSelectionActionModeWithSelectionInternal() { + /** + * If the TextView allows text selection, selects the current word when no existing selection + * was available and starts a drag. + * + * @return true if the drag was started. + */ + private boolean selectCurrentWordAndStartDrag() { if (extractedTextModeWillBeStarted()) { // Cancel the single tap delayed runnable. if (mSelectionModeWithoutSelectionRunnable != null) { mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable); } - return false; } - if (mSelectionActionMode != null) { - // Selection action mode is already started - mSelectionActionMode.invalidate(); + mSelectionActionMode.finish(); + } + if (!checkFieldAndSelectCurrentWord()) { return false; } + getSelectionController().enterDrag(); + return true; + } + /** + * Checks whether a selection can be performed on the current TextView and if so selects + * the current word. + * + * @return true if there already was a selection or if the current word was selected. + */ + private boolean checkFieldAndSelectCurrentWord() { if (!mTextView.canSelectText() || !mTextView.requestFocus()) { Log.w(TextView.LOG_TAG, - "TextView does not support text selection. Action mode cancelled."); + "TextView does not support text selection. Selection cancelled."); return false; } if (!mTextView.hasSelection()) { // There may already be a selection on device rotation - if (!selectCurrentWord()) { - // No word found under cursor or text selection not permitted. - return false; - } + return selectCurrentWord(); + } + return true; + } + + private boolean startSelectionActionModeWithSelectionInternal() { + if (mSelectionActionMode != null) { + // Selection action mode is already started + mSelectionActionMode.invalidate(); + return false; + } + + if (!checkFieldAndSelectCurrentWord()) { + return false; } boolean willExtract = extractedTextModeWillBeStarted(); @@ -1829,12 +1843,18 @@ public class Editor { } if (selectionStart == selectionEnd) { // Spans overlap the cursor. - return true; + for (int i = 0; i < suggestionSpans.length; i++) { + if (suggestionSpans[i].getSuggestions().length > 0) { + return true; + } + } + return false; } int minSpanStart = mTextView.getText().length(); int maxSpanEnd = 0; int unionOfSpansCoveringSelectionStartStart = mTextView.getText().length(); int unionOfSpansCoveringSelectionStartEnd = 0; + boolean hasValidSuggestions = false; for (int i = 0; i < suggestionSpans.length; i++) { final int spanStart = spannable.getSpanStart(suggestionSpans[i]); final int spanEnd = spannable.getSpanEnd(suggestionSpans[i]); @@ -1844,11 +1864,16 @@ public class Editor { // The span doesn't cover the current selection start point. continue; } + hasValidSuggestions = + hasValidSuggestions || suggestionSpans[i].getSuggestions().length > 0; unionOfSpansCoveringSelectionStartStart = Math.min(unionOfSpansCoveringSelectionStartStart, spanStart); unionOfSpansCoveringSelectionStartEnd = Math.max(unionOfSpansCoveringSelectionStartEnd, spanEnd); } + if (!hasValidSuggestions) { + return false; + } if (unionOfSpansCoveringSelectionStartStart >= unionOfSpansCoveringSelectionStartEnd) { // No spans cover the selection start point. return false; @@ -4071,12 +4096,17 @@ public class Editor { offset = getNextCursorOffset(selectionEnd, false); mTouchWordDelta = 0.0f; } - mInWord = !getWordIteratorWithText().isBoundary(offset); positionAtCursorOffset(offset, false); } } @Override + protected void positionAtCursorOffset(int offset, boolean parentScrolled) { + super.positionAtCursorOffset(offset, parentScrolled); + mInWord = !getWordIteratorWithText().isBoundary(offset); + } + + @Override public boolean onTouchEvent(MotionEvent event) { boolean superResult = super.onTouchEvent(event); if (event.getActionMasked() == MotionEvent.ACTION_UP) { @@ -4193,12 +4223,17 @@ public class Editor { offset = getNextCursorOffset(selectionStart, true); mTouchWordDelta = 0.0f; } - mInWord = !getWordIteratorWithText().isBoundary(offset); positionAtCursorOffset(offset, false); } } @Override + protected void positionAtCursorOffset(int offset, boolean parentScrolled) { + super.positionAtCursorOffset(offset, parentScrolled); + mInWord = !getWordIteratorWithText().isBoundary(offset); + } + + @Override public boolean onTouchEvent(MotionEvent event) { boolean superResult = super.onTouchEvent(event); if (event.getActionMasked() == MotionEvent.ACTION_UP) { @@ -4377,7 +4412,7 @@ public class Editor { boolean stayedInArea = distanceSquared < doubleTapSlop * doubleTapSlop; if (stayedInArea && isPositionOnText(eventX, eventY)) { - startSelectionActionModeWithSelectionAndStartDrag(); + selectCurrentWordAndStartDrag(); mDiscardNextActionUp = true; } } @@ -4480,6 +4515,7 @@ public class Editor { mEndHandle.showAtLocation(endOffset); // No longer the first dragging motion, reset. + startSelectionActionModeWithSelection(); mDragAcceleratorActive = false; mStartOffset = -1; } diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index cf67905..ebc7eb3 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -1505,11 +1505,9 @@ public class HorizontalScrollView extends FrameLayout { final int scrollRange = Math.max(0, childWidth - (r - l - mPaddingLeft - mPaddingRight)); if (mSavedState != null) { - if (isLayoutRtl() == mSavedState.isLayoutRtl) { - mScrollX = mSavedState.scrollPosition; - } else { - mScrollX = scrollRange - mSavedState.scrollPosition; - } + mScrollX = isLayoutRtl() + ? scrollRange - mSavedState.scrollOffsetFromStart + : mSavedState.scrollOffsetFromStart; mSavedState = null; } else { if (isLayoutRtl()) { @@ -1692,8 +1690,7 @@ public class HorizontalScrollView extends FrameLayout { } Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); - ss.scrollPosition = mScrollX; - ss.isLayoutRtl = isLayoutRtl(); + ss.scrollOffsetFromStart = isLayoutRtl() ? -mScrollX : mScrollX; return ss; } @@ -1705,8 +1702,7 @@ public class HorizontalScrollView extends FrameLayout { } static class SavedState extends BaseSavedState { - public int scrollPosition; - public boolean isLayoutRtl; + public int scrollOffsetFromStart; SavedState(Parcelable superState) { super(superState); @@ -1714,23 +1710,21 @@ public class HorizontalScrollView extends FrameLayout { public SavedState(Parcel source) { super(source); - scrollPosition = source.readInt(); - isLayoutRtl = (source.readInt() == 0) ? true : false; + scrollOffsetFromStart = source.readInt(); } @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); - dest.writeInt(scrollPosition); - dest.writeInt(isLayoutRtl ? 1 : 0); + dest.writeInt(scrollOffsetFromStart); } @Override public String toString() { return "HorizontalScrollView.SavedState{" + Integer.toHexString(System.identityHashCode(this)) - + " scrollPosition=" + scrollPosition - + " isLayoutRtl=" + isLayoutRtl + "}"; + + " scrollPosition=" + scrollOffsetFromStart + + "}"; } public static final Parcelable.Creator<SavedState> CREATOR diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index 16dc26d..e7d9226 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -16,6 +16,7 @@ package android.widget; +import android.annotation.CallSuper; import android.annotation.IntDef; import android.annotation.Widget; import android.content.Context; @@ -608,7 +609,16 @@ public class NumberPicker extends LinearLayout { mSolidColor = attributesArray.getColor(R.styleable.NumberPicker_solidColor, 0); - mSelectionDivider = attributesArray.getDrawable(R.styleable.NumberPicker_selectionDivider); + final Drawable selectionDivider = attributesArray.getDrawable( + R.styleable.NumberPicker_selectionDivider); + if (selectionDivider != null) { + selectionDivider.setCallback(this); + selectionDivider.setLayoutDirection(getLayoutDirection()); + if (selectionDivider.isStateful()) { + selectionDivider.setState(getDrawableState()); + } + } + mSelectionDivider = selectionDivider; final int defSelectionDividerHeight = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT, @@ -1499,6 +1509,38 @@ public class NumberPicker extends LinearLayout { removeAllCallbacks(); } + @CallSuper + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + + final int[] state = getDrawableState(); + + if (mSelectionDivider != null && mSelectionDivider.isStateful()) { + mSelectionDivider.setState(state); + } + } + + @CallSuper + @Override + public void jumpDrawablesToCurrentState() { + super.jumpDrawablesToCurrentState(); + + if (mSelectionDivider != null) { + mSelectionDivider.jumpToCurrentState(); + } + } + + /** @hide */ + @Override + public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { + super.onResolveDrawables(layoutDirection); + + if (mSelectionDivider != null) { + mSelectionDivider.setLayoutDirection(layoutDirection); + } + } + @Override protected void onDraw(Canvas canvas) { if (!mHasSelectorWheel) { diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java index 2008ba8..3bf9485 100644 --- a/core/java/android/widget/SimpleAdapter.java +++ b/core/java/android/widget/SimpleAdapter.java @@ -51,7 +51,9 @@ import java.util.Map; * </ul> * If no appropriate binding can be found, an {@link IllegalStateException} is thrown. */ -public class SimpleAdapter extends BaseAdapter implements Filterable, Spinner.ThemedSpinnerAdapter { +public class SimpleAdapter extends BaseAdapter implements Filterable, ThemedSpinnerAdapter { + private final LayoutInflater mInflater; + private int[] mTo; private String[] mFrom; private ViewBinder mViewBinder; @@ -60,7 +62,6 @@ public class SimpleAdapter extends BaseAdapter implements Filterable, Spinner.Th private int mResource; private int mDropDownResource; - private LayoutInflater mInflater; /** Layout inflater used for {@link #getDropDownView(int, View, ViewGroup)}. */ private LayoutInflater mDropDownInflater; @@ -174,8 +175,8 @@ public class SimpleAdapter extends BaseAdapter implements Filterable, Spinner.Th @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { - return createViewFromResource( - mDropDownInflater, position, convertView, parent, mDropDownResource); + final LayoutInflater inflater = mDropDownInflater == null ? mInflater : mDropDownInflater; + return createViewFromResource(inflater, position, convertView, parent, mDropDownResource); } private void bindView(int position, View view) { diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java index 095cc44..6fe34dd 100644 --- a/core/java/android/widget/Spinner.java +++ b/core/java/android/widget/Spinner.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.res.Resources; +import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.database.DataSetObserver; import android.graphics.Rect; @@ -217,24 +218,24 @@ public class Spinner extends AbsSpinner implements OnClickListener { * Can be 0 to not look for defaults. * @param mode Constant describing how the user will select choices from * the spinner. - * @param popupContext The context against which the dialog or dropdown - * popup will be inflated. Can be null to use the view - * context. If set, this will override any value - * specified by - * {@link android.R.styleable#Spinner_popupTheme}. + * @param popupTheme The theme against which the dialog or dropdown popup + * should be inflated. May be {@code null} to use the + * view theme. If set, this will override any value + * specified by + * {@link android.R.styleable#Spinner_popupTheme}. * * @see #MODE_DIALOG * @see #MODE_DROPDOWN */ public Spinner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes, int mode, - Context popupContext) { + Theme popupTheme) { super(context, attrs, defStyleAttr, defStyleRes); final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.Spinner, defStyleAttr, defStyleRes); - if (popupContext != null) { - mPopupContext = popupContext; + if (popupTheme != null) { + mPopupContext = new ContextThemeWrapper(context, popupTheme); } else { final int popupThemeResId = a.getResourceId(R.styleable.Spinner_popupTheme, 0); if (popupThemeResId != 0) { @@ -932,9 +933,8 @@ public class Spinner extends AbsSpinner implements OnClickListener { mListAdapter = (ListAdapter) adapter; } - if (dropDownTheme != null && adapter instanceof Spinner.ThemedSpinnerAdapter) { - final Spinner.ThemedSpinnerAdapter themedAdapter = - (Spinner.ThemedSpinnerAdapter) adapter; + if (dropDownTheme != null && adapter instanceof ThemedSpinnerAdapter) { + final ThemedSpinnerAdapter themedAdapter = (ThemedSpinnerAdapter) adapter; if (themedAdapter.getDropDownViewTheme() == null) { themedAdapter.setDropDownViewTheme(dropDownTheme); } @@ -1263,20 +1263,4 @@ public class Spinner extends AbsSpinner implements OnClickListener { } } - public interface ThemedSpinnerAdapter { - /** - * Sets the {@link Resources.Theme} against which drop-down views are - * inflated. - * - * @param theme the context against which to inflate drop-down views - * @see SpinnerAdapter#getDropDownView(int, View, ViewGroup) - */ - public void setDropDownViewTheme(Resources.Theme theme); - - /** - * @return The {@link Resources.Theme} against which drop-down views are - * inflated. - */ - public Resources.Theme getDropDownViewTheme(); - } } diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java index c521f72..27fa3b9 100644 --- a/core/java/android/widget/TabHost.java +++ b/core/java/android/widget/TabHost.java @@ -188,32 +188,9 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1"); mLocalActivityManager = activityGroup; } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - final ViewTreeObserver treeObserver = getViewTreeObserver(); - treeObserver.addOnTouchModeChangeListener(this); - } - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - final ViewTreeObserver treeObserver = getViewTreeObserver(); - treeObserver.removeOnTouchModeChangeListener(this); - } - - /** - * {@inheritDoc} - */ public void onTouchModeChanged(boolean isInTouchMode) { - if (!isInTouchMode) { - // leaving touch mode.. if nothing has focus, let's give it to - // the indicator of the current tab - if (mCurrentView != null && (!mCurrentView.hasFocus() || mCurrentView.isFocused())) { - mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus(); - } - } + // No longer used, but kept to maintain API compatibility. } /** diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index e14e39c..3a85476 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -6680,7 +6680,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener StaticLayout.Builder builder = StaticLayout.Builder.obtain(mHint, 0, mHint.length(), mTextPaint, hintWidth) .setAlignment(alignment) - .setTextDir(mTextDir) + .setTextDirection(mTextDir) .setLineSpacing(mSpacingAdd, mSpacingMult) .setIncludePad(mIncludePad) .setBreakStrategy(mBreakStrategy) @@ -6771,7 +6771,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener StaticLayout.Builder builder = StaticLayout.Builder.obtain(mTransformed, 0, mTransformed.length(), mTextPaint, wantWidth) .setAlignment(alignment) - .setTextDir(mTextDir) + .setTextDirection(mTextDir) .setLineSpacing(mSpacingAdd, mSpacingMult) .setIncludePad(mIncludePad) .setBreakStrategy(mBreakStrategy) diff --git a/core/java/android/widget/ThemedSpinnerAdapter.java b/core/java/android/widget/ThemedSpinnerAdapter.java new file mode 100644 index 0000000..6d92620 --- /dev/null +++ b/core/java/android/widget/ThemedSpinnerAdapter.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.widget; + +import android.annotation.Nullable; +import android.content.res.Resources; +import android.content.res.Resources.Theme; +import android.view.View; +import android.view.ViewGroup; + +/** + * An extension of SpinnerAdapter that is capable of inflating drop-down views + * against a different theme than normal views. + * <p> + * Classes that implement this interface should use the theme provided to + * {@link #setDropDownViewTheme(Theme)} when creating views in + * {@link SpinnerAdapter#getDropDownView(int, View, ViewGroup)}. + */ +public interface ThemedSpinnerAdapter extends SpinnerAdapter { + /** + * Sets the {@link Resources.Theme} against which drop-down views are + * inflated. + * + * @param theme the context against which to inflate drop-down views, or + * {@code null} to use the default theme + * @see SpinnerAdapter#getDropDownView(int, View, ViewGroup) + */ + void setDropDownViewTheme(@Nullable Resources.Theme theme); + + /** + * Returns the value previously set by a call to + * {@link #setDropDownViewTheme(Theme)}. + * + * @return the {@link Resources.Theme} against which drop-down views are + * inflated, or {@code null} if one has not been explicitly set + */ + @Nullable + Resources.Theme getDropDownViewTheme(); +} diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java index ce94727..e607a3f 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java +++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.text.TextUtils; import android.util.Log; +import android.util.Printer; import android.util.Slog; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; @@ -314,6 +315,15 @@ public class InputMethodSubtypeSwitchingController { } return null; } + + protected void dump(final Printer pw, final String prefix) { + final int N = mImeSubtypeList.size(); + for (int i = 0; i < N; ++i) { + final int rank = i; + final ImeSubtypeListItem item = mImeSubtypeList.get(i); + pw.println(prefix + "rank=" + rank + " item=" + item); + } + } } private static class DynamicRotationList { @@ -388,6 +398,14 @@ public class InputMethodSubtypeSwitchingController { } return null; } + + protected void dump(final Printer pw, final String prefix) { + for (int i = 0; i < mUsageHistoryOfSubtypeListItemIndex.length; ++i) { + final int rank = mUsageHistoryOfSubtypeListItemIndex[i]; + final ImeSubtypeListItem item = mImeSubtypeList.get(i); + pw.println(prefix + "rank=" + rank + " item=" + item); + } + } } @VisibleForTesting @@ -478,6 +496,13 @@ public class InputMethodSubtypeSwitchingController { } return result; } + + protected void dump(final Printer pw) { + pw.println(" mSwitchingAwareRotationList:"); + mSwitchingAwareRotationList.dump(pw, " "); + pw.println(" mSwitchingUnawareRotationList:"); + mSwitchingUnawareRotationList.dump(pw, " "); + } } private final InputMethodSettings mSettings; @@ -526,4 +551,12 @@ public class InputMethodSubtypeSwitchingController { return mSubtypeList.getSortedInputMethodAndSubtypeList( showSubtypes, includingAuxiliarySubtypes, isScreenLocked); } + + public void dump(final Printer pw) { + if (mController != null) { + mController.dump(pw); + } else { + pw.println(" mController=null"); + } + } } diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java index 06bdb24..042db71 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java +++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java @@ -379,6 +379,14 @@ public class InputMethodUtils { // The length of localeStr is guaranteed to always return a 1 <= value <= 3 // because localeStr is not empty. if (localeParams.length == 1) { + if (localeParams.length >= 1 && "tl".equals(localeParams[0])) { + // Convert a locale whose language is "tl" to one whose language is "fil". + // For example, "tl_PH" will get converted to "fil_PH". + // Versions of Android earlier than Lollipop did not support three letter language + // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino). + // On Lollipop and above, the current three letter version must be used. + localeParams[0] = "fil"; + } return new Locale(localeParams[0]); } else if (localeParams.length == 2) { return new Locale(localeParams[0], localeParams[1]); @@ -397,7 +405,7 @@ public class InputMethodUtils { for (int i = 0; i < N; ++i) { final InputMethodSubtype subtype = imi.getSubtypeAt(i); if (checkCountry) { - final Locale subtypeLocale = constructLocaleFromString(subtype.getLocale()); + final Locale subtypeLocale = subtype.getLocaleObject(); if (subtypeLocale == null || !TextUtils.equals(subtypeLocale.getLanguage(), locale.getLanguage()) || !TextUtils.equals(subtypeLocale.getCountry(), locale.getCountry())) { diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 22c0680..14065b1 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -289,6 +289,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private Rect mTempRect; private Rect mOutsets = new Rect(); + private boolean mIsStartingWindow; + static class WindowManagerHolder { static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); @@ -3891,7 +3893,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // A pending invalidation will typically be resolved before the posted message // would run normally in order to satisfy instance state restoration. PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false); - if (!isDestroyed() && (st == null || st.menu == null)) { + if (!isDestroyed() && (st == null || st.menu == null) && !mIsStartingWindow) { invalidatePanelMenu(FEATURE_ACTION_BAR); } } else { @@ -4966,4 +4968,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mDecor.updateColorViews(null, false /* animate */); } } + + public void setIsStartingWindow(boolean isStartingWindow) { + mIsStartingWindow = isStartingWindow; + } } diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index 1fc0ac3..c77d614 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -37,6 +37,7 @@ import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.Window; +import android.view.WindowInsets; import android.view.WindowManager; import android.view.animation.Animation; import android.view.animation.AnimationSet; @@ -83,7 +84,7 @@ public final class FloatingToolbar { private final Rect mContentRect = new Rect(); private Menu mMenu; - private List<CharSequence> mShowingTitles = new ArrayList<CharSequence>(); + private List<Object> mShowingMenuItems = new ArrayList<Object>(); private MenuItem.OnMenuItemClickListener mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER; private int mSuggestedWidth; @@ -155,7 +156,7 @@ public final class FloatingToolbar { if (!isCurrentlyShowing(menuItems) || mWidthChanged) { mPopup.dismiss(); mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth); - mShowingTitles = getMenuItemTitles(menuItems); + mShowingMenuItems = getShowingMenuItemsReferences(menuItems); } mPopup.updateCoordinates(mContentRect); if (!mPopup.isShowing()) { @@ -210,7 +211,7 @@ public final class FloatingToolbar { * Returns true if this floating toolbar is currently showing the specified menu items. */ private boolean isCurrentlyShowing(List<MenuItem> menuItems) { - return mShowingTitles.equals(getMenuItemTitles(menuItems)); + return mShowingMenuItems.equals(getShowingMenuItemsReferences(menuItems)); } /** @@ -233,12 +234,16 @@ public final class FloatingToolbar { return menuItems; } - private List<CharSequence> getMenuItemTitles(List<MenuItem> menuItems) { - List<CharSequence> titles = new ArrayList<CharSequence>(); + private List<Object> getShowingMenuItemsReferences(List<MenuItem> menuItems) { + List<Object> references = new ArrayList<Object>(); for (MenuItem menuItem : menuItems) { - titles.add(menuItem.getTitle()); + if (isIconOnlyMenuItem(menuItem)) { + references.add(menuItem.getIcon()); + } else { + references.add(menuItem.getTitle()); + } } - return titles; + return references; } @@ -289,7 +294,6 @@ public final class FloatingToolbar { public void onAnimationRepeat(Animation animation) { } }; - private final AnimatorSet mShowAnimation; private final AnimatorSet mDismissAnimation; private final AnimatorSet mHideAnimation; private final AnimationSet mOpenOverflowAnimation = new AnimationSet(true) { @@ -324,6 +328,7 @@ public final class FloatingToolbar { } }; + private final Rect mViewPort = new Rect(); private final Point mCoords = new Point(); private final Region mTouchableRegion = new Region(); @@ -353,14 +358,9 @@ public final class FloatingToolbar { * from. */ public FloatingToolbarPopup(View parent) { - mMarginHorizontal = parent.getResources() - .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin); - mMarginVertical = parent.getResources() - .getDimensionPixelSize(R.dimen.floating_toolbar_vertical_margin); mParent = Preconditions.checkNotNull(parent); mContentContainer = createContentContainer(parent.getContext()); mPopupWindow = createPopupWindow(mContentContainer); - mShowAnimation = createGrowFadeInFromBottom(mContentContainer, mMarginHorizontal); mDismissAnimation = createShrinkFadeOutFromBottomAnimation( mContentContainer, 150, // startDelay @@ -380,6 +380,10 @@ public final class FloatingToolbar { mPopupWindow.dismiss(); } }); + mMarginHorizontal = parent.getResources() + .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin); + mMarginVertical = parent.getResources() + .getDimensionPixelSize(R.dimen.floating_toolbar_vertical_margin); } /** @@ -396,7 +400,7 @@ public final class FloatingToolbar { mMainPanel = new FloatingToolbarMainPanel(mParent.getContext(), mOpenOverflow); } List<MenuItem> overflowMenuItems = - mMainPanel.layoutMenuItems(menuItems, suggestedWidth); + mMainPanel.layoutMenuItems(menuItems, getToolbarWidth(suggestedWidth)); mMainPanel.setOnMenuItemClickListener(menuItemClickListener); if (!overflowMenuItems.isEmpty()) { if (mOverflowPanel == null) { @@ -432,7 +436,8 @@ public final class FloatingToolbar { // The "show" animation will make this visible. mContentContainer.setAlpha(0); } - updateOverflowHeight(contentRect.top - (mMarginVertical * 2)); + refreshViewPort(); + updateOverflowHeight(contentRect.top - (mMarginVertical * 2) - mViewPort.top); refreshCoordinatesAndOverflowDirection(contentRect); preparePopupContent(); mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, mCoords.x, mCoords.y); @@ -496,6 +501,7 @@ public final class FloatingToolbar { } cancelOverflowAnimations(); + refreshViewPort(); refreshCoordinatesAndOverflowDirection(contentRect); preparePopupContent(); mPopupWindow.update(mCoords.x, mCoords.y, getWidth(), getHeight()); @@ -523,18 +529,24 @@ public final class FloatingToolbar { } private void refreshCoordinatesAndOverflowDirection(Rect contentRect) { + // NOTE: Ensure that mViewPort has been refreshed before this. + int x = contentRect.centerX() - getWidth() / 2; int y; - if (contentRect.top > getHeight()) { + if (contentRect.top - getHeight() > mViewPort.top) { y = contentRect.top - getHeight(); mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_UP; - } else if (contentRect.top > getToolbarHeightWithVerticalMargin()) { + } else if (contentRect.top - getToolbarHeightWithVerticalMargin() > mViewPort.top) { y = contentRect.top - getToolbarHeightWithVerticalMargin(); mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; } else { y = contentRect.bottom; mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN; } + + // Update x so that the toolbar isn't rendered behind the nav bar in landscape. + x = Math.max(0, Math.min(x, mViewPort.right - getWidth())); + mCoords.set(x, y); if (mOverflowPanel != null) { mOverflowPanel.setOverflowDirection(mOverflowDirection); @@ -549,7 +561,7 @@ public final class FloatingToolbar { * Performs the "show" animation on the floating popup. */ private void runShowAnimation() { - mShowAnimation.start(); + createGrowFadeInFromBottom(mContentContainer).start(); } /** @@ -597,7 +609,6 @@ public final class FloatingToolbar { final float startY = mContentContainer.getY(); final float left = mContentContainer.getX(); final float right = left + mContentContainer.getWidth(); - final boolean rtl = mContentContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; Animation widthAnimation = new Animation() { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { @@ -605,7 +616,7 @@ public final class FloatingToolbar { int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth)); params.width = startWidth + deltaWidth; mContentContainer.setLayoutParams(params); - if (rtl) { + if (isRTL()) { mContentContainer.setX(left); } else { mContentContainer.setX(right - mContentContainer.getWidth()); @@ -656,7 +667,6 @@ public final class FloatingToolbar { final boolean morphedUpwards = (mOverflowDirection == OVERFLOW_DIRECTION_UP); final float left = mContentContainer.getX(); final float right = left + mContentContainer.getWidth(); - final boolean rtl = mContentContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; Animation widthAnimation = new Animation() { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { @@ -664,7 +674,7 @@ public final class FloatingToolbar { int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth)); params.width = startWidth + deltaWidth; mContentContainer.setLayoutParams(params); - if (rtl) { + if (isRTL()) { mContentContainer.setX(left); } else { mContentContainer.setX(right - mContentContainer.getWidth()); @@ -777,8 +787,13 @@ public final class FloatingToolbar { */ private void positionOverflowPanel() { Preconditions.checkNotNull(mOverflowPanel); - float x = mPopupWindow.getWidth() + float x; + if (isRTL()) { + x = mMarginHorizontal; + } else { + x = mPopupWindow.getWidth() - (mOverflowPanel.getView().getMeasuredWidth() + mMarginHorizontal); + } mContentContainer.setX(x); mContentContainer.setY(mMarginVertical); setContentAreaAsTouchableSurface(); @@ -820,6 +835,29 @@ public final class FloatingToolbar { mPopupWindow.setHeight(height + mMarginVertical * 2); } + + private void refreshViewPort() { + mParent.getGlobalVisibleRect(mViewPort); + WindowInsets windowInsets = mParent.getRootWindowInsets(); + mViewPort.set( + mViewPort.left + windowInsets.getStableInsetLeft(), + mViewPort.top + windowInsets.getStableInsetTop(), + mViewPort.right - windowInsets.getStableInsetRight(), + mViewPort.bottom - windowInsets.getStableInsetBottom()); + } + + private int getToolbarWidth(int suggestedWidth) { + int width = suggestedWidth; + refreshViewPort(); + int maximumWidth = mViewPort.width() - 2 * mParent.getResources() + .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin); + if (width <= 0) { + width = mParent.getResources() + .getDimensionPixelSize(R.dimen.floating_toolbar_preferred_width); + } + return Math.min(width, maximumWidth); + } + /** * Sets the touchable region of this popup to be zero. This means that all touch events on * this popup will go through to the surface behind it. @@ -856,6 +894,10 @@ public final class FloatingToolbar { viewTreeObserver.removeOnComputeInternalInsetsListener(mInsetsComputer); viewTreeObserver.addOnComputeInternalInsetsListener(mInsetsComputer); } + + private boolean isRTL() { + return mContentContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + } } /** @@ -901,12 +943,11 @@ public final class FloatingToolbar { * * @return The menu items that are not included in this main panel. */ - public List<MenuItem> layoutMenuItems(List<MenuItem> menuItems, int suggestedWidth) { + public List<MenuItem> layoutMenuItems(List<MenuItem> menuItems, int width) { Preconditions.checkNotNull(menuItems); - final int toolbarWidth = getAdjustedToolbarWidth(mContext, suggestedWidth) - // Reserve space for the "open overflow" button. - - getEstimatedOpenOverflowButtonWidth(mContext); + // Reserve space for the "open overflow" button. + final int toolbarWidth = width - getEstimatedOpenOverflowButtonWidth(mContext); int availableWidth = toolbarWidth; final LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems); @@ -1332,14 +1373,14 @@ public final class FloatingToolbar { * * @param view The view to animate */ - private static AnimatorSet createGrowFadeInFromBottom(View view, int x) { + private static AnimatorSet createGrowFadeInFromBottom(View view) { AnimatorSet growFadeInFromBottomAnimation = new AnimatorSet(); growFadeInFromBottomAnimation.playTogether( ObjectAnimator.ofFloat(view, View.SCALE_X, 0.5f, 1).setDuration(125), ObjectAnimator.ofFloat(view, View.SCALE_Y, 0.5f, 1).setDuration(125), ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(75), // Make sure that view.x is always fixed throughout the duration of this animation. - ObjectAnimator.ofFloat(view, View.X, x, x)); + ObjectAnimator.ofFloat(view, View.X, view.getX(), view.getX())); growFadeInFromBottomAnimation.setStartDelay(50); return growFadeInFromBottomAnimation; } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index aee0ff6..86d11be 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -841,7 +841,7 @@ public class LockPatternUtils { final byte[] bytes = string.getBytes(); for (int i = 0; i < bytes.length; i++) { - byte b = bytes[i]; + byte b = (byte) (bytes[i] - '1'); result.add(LockPatternView.Cell.of(b / 3, b % 3)); } return result; @@ -861,7 +861,21 @@ public class LockPatternUtils { byte[] res = new byte[patternSize]; for (int i = 0; i < patternSize; i++) { LockPatternView.Cell cell = pattern.get(i); - res[i] = (byte) (cell.getRow() * 3 + cell.getColumn()); + res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1'); + } + return new String(res); + } + + public static String patternStringToBaseZero(String pattern) { + if (pattern == null) { + return ""; + } + final int patternSize = pattern.length(); + + byte[] res = new byte[patternSize]; + final byte[] bytes = pattern.getBytes(); + for (int i = 0; i < patternSize; i++) { + res[i] = (byte) (bytes[i] - '1'); } return new String(res); } |
