diff options
Diffstat (limited to 'core/java/android')
53 files changed, 1218 insertions, 252 deletions
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index aa7692b..dd3d3a8 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -43,6 +43,7 @@ import com.google.android.collect.Maps; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; @@ -2259,6 +2260,9 @@ public class AccountManager { } /** + * Deprecated in favor of {@link #newChooseAccountIntent(Account, List, String[], String, + * String, String[], Bundle)}. + * * Returns an intent to an {@link Activity} that prompts the user to choose from a list of * accounts. * The caller will then typically start the activity by calling @@ -2273,14 +2277,13 @@ public class AccountManager { * null, null, null);</pre> * @param selectedAccount if specified, indicates that the {@link Account} is the currently * selected one, according to the caller's definition of selected. - * @param allowableAccounts an optional {@link ArrayList} of accounts that are allowed to be + * @param allowableAccounts an optional {@link List} of accounts that are allowed to be * shown. If not specified then this field will not limit the displayed accounts. * @param allowableAccountTypes an optional string array of account types. These are used * both to filter the shown accounts and to filter the list of account types that are shown * when adding an account. If not specified then this field will not limit the displayed * account types when adding an account. - * @param alwaysPromptForAccount if set the account chooser screen is always shown, otherwise - * it is only shown when there is more than one account from which to choose + * @param alwaysPromptForAccount boolean that is ignored. * @param descriptionOverrideText if non-null this string is used as the description in the * accounts chooser screen rather than the default * @param addAccountAuthTokenType this string is passed as the {@link #addAccount} @@ -2291,7 +2294,9 @@ public class AccountManager { * parameter * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow. */ - static public Intent newChooseAccountIntent(Account selectedAccount, + @Deprecated + static public Intent newChooseAccountIntent( + Account selectedAccount, ArrayList<Account> allowableAccounts, String[] allowableAccountTypes, boolean alwaysPromptForAccount, @@ -2299,20 +2304,67 @@ public class AccountManager { String addAccountAuthTokenType, String[] addAccountRequiredFeatures, Bundle addAccountOptions) { + return newChooseAccountIntent( + selectedAccount, + allowableAccounts, + allowableAccountTypes, + descriptionOverrideText, + addAccountAuthTokenType, + addAccountRequiredFeatures, + addAccountOptions); + } + + /** + * Returns an intent to an {@link Activity} that prompts the user to choose from a list of + * accounts. + * The caller will then typically start the activity by calling + * <code>startActivityForResult(intent, ...);</code>. + * <p> + * On success the activity returns a Bundle with the account name and type specified using + * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}. + * <p> + * The most common case is to call this with one account type, e.g.: + * <p> + * <pre> newChooseAccountIntent(null, null, new String[]{"com.google"}, null, null, null, + * null);</pre> + * @param selectedAccount if specified, indicates that the {@link Account} is the currently + * selected one, according to the caller's definition of selected. + * @param allowableAccounts an optional {@link List} of accounts that are allowed to be + * shown. If not specified then this field will not limit the displayed accounts. + * @param allowableAccountTypes an optional string array of account types. These are used + * both to filter the shown accounts and to filter the list of account types that are shown + * when adding an account. If not specified then this field will not limit the displayed + * account types when adding an account. + * @param descriptionOverrideText if non-null this string is used as the description in the + * accounts chooser screen rather than the default + * @param addAccountAuthTokenType this string is passed as the {@link #addAccount} + * authTokenType parameter + * @param addAccountRequiredFeatures this string array is passed as the {@link #addAccount} + * requiredFeatures parameter + * @param addAccountOptions This {@link Bundle} is passed as the {@link #addAccount} options + * parameter + * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow. + */ + static public Intent newChooseAccountIntent( + Account selectedAccount, + List<Account> allowableAccounts, + String[] allowableAccountTypes, + String descriptionOverrideText, + String addAccountAuthTokenType, + String[] addAccountRequiredFeatures, + Bundle addAccountOptions) { Intent intent = new Intent(); ComponentName componentName = ComponentName.unflattenFromString( Resources.getSystem().getString(R.string.config_chooseTypeAndAccountActivity)); intent.setClassName(componentName.getPackageName(), componentName.getClassName()); intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST, - allowableAccounts); + allowableAccounts == null ? null : new ArrayList<Account>(allowableAccounts)); intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY, allowableAccountTypes); intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE, addAccountOptions); intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_SELECTED_ACCOUNT, selectedAccount); - intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, - alwaysPromptForAccount); intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_DESCRIPTION_TEXT_OVERRIDE, descriptionOverrideText); intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING, diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java index c06b462..133df2b 100644 --- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java +++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java @@ -88,9 +88,10 @@ public class ChooseTypeAndAccountActivity extends Activity public static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount"; /** - * If true then display the account selection list even if there is just - * one account to choose from. boolean. + * Deprecated. Providing this extra to {@link ChooseTypeAndAccountActivity} + * will have no effect. */ + @Deprecated public static final String EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT = "alwaysPromptForAccount"; @@ -117,7 +118,6 @@ public class ChooseTypeAndAccountActivity extends Activity private Set<String> mSetOfRelevantAccountTypes; private String mSelectedAccountName = null; private boolean mSelectedAddNewAccount = false; - private boolean mAlwaysPromptForAccount = false; private String mDescriptionOverride; private ArrayList<Account> mAccounts; @@ -188,7 +188,6 @@ public class ChooseTypeAndAccountActivity extends Activity mSetOfAllowableAccounts = getAllowableAccountSet(intent); mSetOfRelevantAccountTypes = getReleventAccountTypes(intent); - mAlwaysPromptForAccount = intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false); mDescriptionOverride = intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE); mAccounts = getAcceptableAccountChoices(AccountManager.get(this)); @@ -218,15 +217,6 @@ public class ChooseTypeAndAccountActivity extends Activity } else { startChooseAccountTypeActivity(); } - return; - } - - // if there is only one allowable account return it - if (!mAlwaysPromptForAccount && mAccounts.size() == 1) { - Account account = mAccounts.get(0); - super.onCreate(savedInstanceState); - setResultAndFinish(account.name, account.type); - return; } } diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java index 4d34349..72f8c77 100644 --- a/core/java/android/app/ActionBar.java +++ b/core/java/android/app/ActionBar.java @@ -1057,6 +1057,11 @@ public abstract class ActionBar { } /** @hide */ + public boolean onKeyShortcut(int keyCode, KeyEvent event) { + return false; + } + + /** @hide */ public boolean collapseActionView() { return false; } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index d07238a..7572799 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2469,7 +2469,9 @@ public class Activity extends ContextThemeWrapper * @return True if the key shortcut was handled. */ public boolean onKeyShortcut(int keyCode, KeyEvent event) { - return false; + // Let the Action Bar have a chance at handling the shortcut. + ActionBar actionBar = getActionBar(); + return (actionBar != null && actionBar.onKeyShortcut(keyCode, event)); } /** diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index cc93ac9..fc408a8 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -456,14 +456,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM int resultCode = data.readInt(); String resultData = data.readString(); Bundle resultExtras = data.readBundle(); - String perm = data.readString(); + String[] perms = data.readStringArray(); int appOp = data.readInt(); Bundle options = data.readBundle(); boolean serialized = data.readInt() != 0; boolean sticky = data.readInt() != 0; int userId = data.readInt(); int res = broadcastIntent(app, intent, resolvedType, resultTo, - resultCode, resultData, resultExtras, perm, appOp, + resultCode, resultData, resultExtras, perms, appOp, options, serialized, sticky, userId); reply.writeNoException(); reply.writeInt(res); @@ -3007,7 +3007,7 @@ class ActivityManagerProxy implements IActivityManager public int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, - String requiredPermission, int appOp, Bundle options, boolean serialized, + String[] requiredPermissions, int appOp, Bundle options, boolean serialized, boolean sticky, int userId) throws RemoteException { Parcel data = Parcel.obtain(); @@ -3020,7 +3020,7 @@ class ActivityManagerProxy implements IActivityManager data.writeInt(resultCode); data.writeString(resultData); data.writeBundle(map); - data.writeString(requiredPermission); + data.writeStringArray(requiredPermissions); data.writeInt(appOp); data.writeBundle(options); data.writeInt(serialized ? 1 : 0); diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index fa81412..e28fb20 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -217,11 +217,6 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { } protected void viewsReady(ArrayMap<String, View> sharedElements) { - final View decor = getDecor(); - final ViewRootImpl viewRoot = decor == null ? null : decor.getViewRootImpl(); - if (viewRoot != null) { - viewRoot.setPausedForTransition(true); - } sharedElements.retainAll(mAllSharedElementNames); if (mListener != null) { mListener.onMapSharedElements(mAllSharedElementNames, sharedElements); @@ -905,6 +900,14 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { } } + protected void pauseInput() { + final View decor = getDecor(); + final ViewRootImpl viewRoot = decor == null ? null : decor.getViewRootImpl(); + if (viewRoot != null) { + viewRoot.setPausedForTransition(true); + } + } + protected void onTransitionsComplete() {} protected class ContinueTransitionListener extends Transition.TransitionListenerAdapter { diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index bf3bfae..08e1696 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -233,8 +233,10 @@ public class AppOpsManager { public static final int OP_READ_EXTERNAL_STORAGE = 59; /** @hide Write external storage. */ public static final int OP_WRITE_EXTERNAL_STORAGE = 60; + /** @hide Turned on the screen. */ + public static final int OP_TURN_SCREEN_ON = 61; /** @hide */ - public static final int _NUM_OP = 61; + public static final int _NUM_OP = 62; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; @@ -393,7 +395,8 @@ public class AppOpsManager { OP_READ_CELL_BROADCASTS, OP_MOCK_LOCATION, OP_READ_EXTERNAL_STORAGE, - OP_WRITE_EXTERNAL_STORAGE + OP_WRITE_EXTERNAL_STORAGE, + OP_TURN_SCREEN_ON, }; /** @@ -461,7 +464,8 @@ public class AppOpsManager { OPSTR_READ_CELL_BROADCASTS, OPSTR_MOCK_LOCATION, OPSTR_READ_EXTERNAL_STORAGE, - OPSTR_WRITE_EXTERNAL_STORAGE + OPSTR_WRITE_EXTERNAL_STORAGE, + null, }; /** @@ -528,8 +532,9 @@ public class AppOpsManager { "BODY_SENSORS", "READ_CELL_BROADCASTS", "MOCK_LOCATION", - "OPSTR_READ_EXTERNAL_STORAGE", - "OPSTR_WRITE_EXTERNAL_STORAGE", + "READ_EXTERNAL_STORAGE", + "WRITE_EXTERNAL_STORAGE", + "TURN_ON_SCREEN", }; /** @@ -598,6 +603,7 @@ public class AppOpsManager { null, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, + null, // no permission for turning the screen on }; /** @@ -666,7 +672,8 @@ public class AppOpsManager { null, // READ_CELL_BROADCASTS null, // MOCK_LOCATION null, // READ_EXTERNAL_STORAGE - null // WRITE_EXTERNAL_STORAGE + null, // WRITE_EXTERNAL_STORAGE + null, // TURN_ON_SCREEN }; /** @@ -734,7 +741,8 @@ public class AppOpsManager { false, // READ_CELL_BROADCASTS false, // MOCK_LOCATION false, // READ_EXTERNAL_STORAGE - false // WRITE_EXTERNAL_STORAGE + false, // WRITE_EXTERNAL_STORAGE + false, // TURN_ON_SCREEN }; /** @@ -765,7 +773,7 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, - AppOpsManager.MODE_ALLOWED, + AppOpsManager.MODE_DEFAULT, // OP_SYSTEM_ALERT_WINDOW AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, @@ -801,7 +809,8 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ERRORED, // OP_MOCK_LOCATION AppOpsManager.MODE_ALLOWED, - AppOpsManager.MODE_ALLOWED + AppOpsManager.MODE_ALLOWED, + AppOpsManager.MODE_ALLOWED, // OP_TURN_ON_SCREEN }; /** @@ -872,7 +881,8 @@ public class AppOpsManager { false, false, false, - false + false, + false, }; /** diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 6639486..235f294 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -180,7 +180,7 @@ class ContextImpl extends Context { @GuardedBy("mSync") private File[] mExternalMediaDirs; - private static final String[] EMPTY_FILE_LIST = {}; + private static final String[] EMPTY_STRING_ARRAY = {}; // The system service cache for the system services that are cached per-ContextImpl. final Object[] mServiceCache = SystemServiceRegistry.createServiceCache(); @@ -552,7 +552,7 @@ class ContextImpl extends Context { @Override public String[] fileList() { final String[] list = getFilesDir().list(); - return (list != null) ? list : EMPTY_FILE_LIST; + return (list != null) ? list : EMPTY_STRING_ARRAY; } @Override @@ -591,7 +591,7 @@ class ContextImpl extends Context { @Override public String[] databaseList() { final String[] list = getDatabasesDir().list(); - return (list != null) ? list : EMPTY_FILE_LIST; + return (list != null) ? list : EMPTY_STRING_ARRAY; } @@ -777,11 +777,28 @@ class ContextImpl extends Context { public void sendBroadcast(Intent intent, String receiverPermission) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + String[] receiverPermissions = receiverPermission == null ? null + : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, + Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, + null, false, false, getUserId()); + } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); + } + } + + @Override + public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) { + warnIfCallingFromSystemProcess(); + String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + try { + intent.prepareToLeaveProcess(); + ActivityManagerNative.getDefault().broadcastIntent( + mMainThread.getApplicationThread(), intent, resolvedType, null, + Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, null, false, false, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); @@ -792,11 +809,13 @@ class ContextImpl extends Context { public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + String[] receiverPermissions = receiverPermission == null ? null + : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, + Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, options, false, false, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); @@ -807,11 +826,13 @@ class ContextImpl extends Context { public void sendBroadcast(Intent intent, String receiverPermission, int appOp) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + String[] receiverPermissions = receiverPermission == null ? null + : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, receiverPermission, appOp, null, false, false, + Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); @@ -822,11 +843,13 @@ class ContextImpl extends Context { public void sendOrderedBroadcast(Intent intent, String receiverPermission) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + String[] receiverPermissions = receiverPermission == null ? null + : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, + Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, null, true, false, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); @@ -883,11 +906,13 @@ class ContextImpl extends Context { } } String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + String[] receiverPermissions = receiverPermission == null ? null + : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, rd, - initialCode, initialData, initialExtras, receiverPermission, appOp, + initialCode, initialData, initialExtras, receiverPermissions, appOp, options, true, false, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); @@ -917,11 +942,13 @@ class ContextImpl extends Context { public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, int appOp) { String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + String[] receiverPermissions = receiverPermission == null ? null + : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, receiverPermission, appOp, null, false, false, + Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false, user.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); @@ -933,14 +960,21 @@ class ContextImpl extends Context { String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { sendOrderedBroadcastAsUser(intent, user, receiverPermission, AppOpsManager.OP_NONE, - resultReceiver, scheduler, initialCode, initialData, initialExtras); + null, resultReceiver, scheduler, initialCode, initialData, initialExtras); } @Override public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, int appOp, BroadcastReceiver resultReceiver, - Handler scheduler, - int initialCode, String initialData, Bundle initialExtras) { + Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { + sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, + null, resultReceiver, scheduler, initialCode, initialData, initialExtras); + } + + @Override + public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, + String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver, + Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { IIntentReceiver rd = null; if (resultReceiver != null) { if (mPackageInfo != null) { @@ -954,17 +988,19 @@ class ContextImpl extends Context { if (scheduler == null) { scheduler = mMainThread.getHandler(); } - rd = new LoadedApk.ReceiverDispatcher( - resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver(); + rd = new LoadedApk.ReceiverDispatcher(resultReceiver, getOuterContext(), + scheduler, null, false).getIIntentReceiver(); } } String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + String[] receiverPermissions = receiverPermission == null ? null + : new String[] {receiverPermission}; try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, rd, - initialCode, initialData, initialExtras, receiverPermission, - appOp, null, true, false, user.getIdentifier()); + initialCode, initialData, initialExtras, receiverPermissions, + appOp, options, true, false, user.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -1925,13 +1961,14 @@ class ContextImpl extends Context { // enough permissions; ask vold to create on our behalf. final IMountService mount = IMountService.Stub.asInterface( ServiceManager.getService("mount")); - int res = -1; try { - res = mount.mkdirs(getPackageName(), dir.getAbsolutePath()); - } catch (Exception ignored) { - } - if (res != 0) { - Log.w(TAG, "Failed to ensure directory: " + dir); + final int res = mount.mkdirs(getPackageName(), dir.getAbsolutePath()); + if (res != 0) { + Log.w(TAG, "Failed to ensure " + dir + ": " + res); + dir = null; + } + } catch (Exception e) { + Log.w(TAG, "Failed to ensure " + dir + ": " + e); dir = null; } } diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java index 05cf1d4..0745537 100644 --- a/core/java/android/app/EnterTransitionCoordinator.java +++ b/core/java/android/app/EnterTransitionCoordinator.java @@ -333,6 +333,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { boolean startSharedElementTransition = true; setGhostVisibility(View.INVISIBLE); scheduleGhostVisibilityChange(View.INVISIBLE); + pauseInput(); Transition transition = beginTransition(decorView, startEnterTransition, startSharedElementTransition); scheduleGhostVisibilityChange(View.VISIBLE); diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java index 9ddebb0..ad104a4 100644 --- a/core/java/android/app/ExitTransitionCoordinator.java +++ b/core/java/android/app/ExitTransitionCoordinator.java @@ -203,6 +203,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { public void startExit() { if (!mIsExitStarted) { mIsExitStarted = true; + pauseInput(); ViewGroup decorView = getDecor(); if (decorView != null) { decorView.suppressLayout(true); @@ -220,6 +221,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { public void startExit(int resultCode, Intent data) { if (!mIsExitStarted) { mIsExitStarted = true; + pauseInput(); ViewGroup decorView = getDecor(); if (decorView != null) { decorView.suppressLayout(true); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index acce81c..1d87d77 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -106,7 +106,7 @@ public interface IActivityManager extends IInterface { public void unregisterReceiver(IIntentReceiver receiver) throws RemoteException; public int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, - String resultData, Bundle map, String requiredPermission, + String resultData, Bundle map, String[] requiredPermissions, int appOp, Bundle options, boolean serialized, boolean sticky, int userId) throws RemoteException; public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) throws RemoteException; public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java index 9673c98..40126d6 100644 --- a/core/java/android/app/assist/AssistStructure.java +++ b/core/java/android/app/assist/AssistStructure.java @@ -812,7 +812,7 @@ public class AssistStructure implements Parcelable { * Returns true if assist data has been blocked starting at this node in the hierarchy. */ public boolean isAssistBlocked() { - return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) == 0; + return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) != 0; } /** diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index c96fe71..d27dfa0 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -92,7 +92,8 @@ public final class BluetoothDevice implements Parcelable { * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or * {@link #EXTRA_RSSI} if they are available. - * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} and + * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to receive. */ // TODO: Change API to not broadcast RSSI if not available (incoming connection) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java index 6302521..fb81fd1 100644 --- a/core/java/android/bluetooth/BluetoothSocket.java +++ b/core/java/android/bluetooth/BluetoothSocket.java @@ -240,6 +240,8 @@ public final class BluetoothSocket implements Closeable { as.close(); throw new IOException("bt socket acept failed"); } + + as.mPfd = new ParcelFileDescriptor(fds[0]); as.mSocket = new LocalSocket(fds[0]); as.mSocketIS = as.mSocket.getInputStream(); as.mSocketOS = as.mSocket.getOutputStream(); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 675515b..4c7dd10 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1516,6 +1516,33 @@ public abstract class Context { public abstract void sendBroadcast(Intent intent, @Nullable String receiverPermission); + + /** + * Broadcast the given intent to all interested BroadcastReceivers, allowing + * an array of required permissions to be enforced. This call is asynchronous; it returns + * immediately, and you will continue executing while the receivers are run. No results are + * propagated from receivers and receivers can not abort the broadcast. If you want to allow + * receivers to propagate results or abort the broadcast, you must send an ordered broadcast + * using {@link #sendOrderedBroadcast(Intent, String)}. + * + * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts. + * + * @param intent The Intent to broadcast; all receivers matching this + * Intent will receive the broadcast. + * @param receiverPermissions Array of names of permissions that a receiver must hold + * in order to receive your broadcast. + * If null or empty, no permissions are required. + * + * @see android.content.BroadcastReceiver + * @see #registerReceiver + * @see #sendBroadcast(Intent) + * @see #sendOrderedBroadcast(Intent, String) + * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) + * @hide + */ + public abstract void sendBroadcastMultiplePermissions(Intent intent, + String[] receiverPermissions); + /** * Broadcast the given intent to all interested BroadcastReceivers, allowing * an optional required permission to be enforced. This @@ -1782,6 +1809,17 @@ public abstract class Context { @Nullable Bundle initialExtras); /** + * Similar to above but takes an appOp as well, to enforce restrictions, and an options Bundle. + * @see #sendOrderedBroadcastAsUser(Intent, UserHandle, String, + * BroadcastReceiver, Handler, int, String, Bundle) + * @hide + */ + public abstract void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, + @Nullable String receiverPermission, int appOp, @Nullable Bundle options, + BroadcastReceiver resultReceiver, @Nullable Handler scheduler, int initialCode, + @Nullable String initialData, @Nullable Bundle initialExtras); + + /** * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the * Intent you are sending stays around after the broadcast is complete, * so that others can quickly retrieve that data through the return diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index 4e7c832..8359edf 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -402,6 +402,12 @@ public class ContextWrapper extends Context { } /** @hide */ + @Override + public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) { + mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions); + } + + /** @hide */ @SystemApi @Override public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) { @@ -483,12 +489,20 @@ public class ContextWrapper extends Context { @Override public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, int appOp, BroadcastReceiver resultReceiver, - Handler scheduler, - int initialCode, String initialData, Bundle initialExtras) { + Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, resultReceiver, scheduler, initialCode, initialData, initialExtras); } + /** @hide */ + @Override + public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user, + String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver, + Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { + mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, options, + resultReceiver, scheduler, initialCode, initialData, initialExtras); + } + @Override @Deprecated public void sendStickyBroadcast(Intent intent) { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index c9f9b56..5571662 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3094,6 +3094,13 @@ public class Intent implements Parcelable, Cloneable { @SdkConstant(SdkConstantType.INTENT_CATEGORY) public static final String CATEGORY_HOME = "android.intent.category.HOME"; /** + * This is the setup wizard activity, that is the first activity that is displayed + * when the user sets up the device for the first time. + * @hide + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_SETUP_WIZARD = "android.intent.category.SETUP_WIZARD"; + /** * This activity is a preference panel. */ @SdkConstant(SdkConstantType.INTENT_CATEGORY) diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 103ee29..ceb610a 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -502,9 +502,6 @@ interface IPackageManager { void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener); void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener); - - int getMountExternalMode(int uid); - void grantDefaultPermissionsToEnabledCarrierApps(in String[] packageNames, int userId); boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId); diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java index 96000dd..4dbac05 100644 --- a/core/java/android/content/pm/IntentFilterVerificationInfo.java +++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java @@ -26,7 +26,9 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; + import com.android.internal.util.XmlUtils; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -181,14 +183,28 @@ public final class IntentFilterVerificationInfo implements Parcelable { return getStatusStringFromValue(mMainStatus); } - public static String getStatusStringFromValue(int val) { - switch (val) { - case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK : return "ask"; - case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS : return "always"; - case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER : return "never"; + public static String getStatusStringFromValue(long val) { + StringBuilder sb = new StringBuilder(); + switch ((int)(val >> 32)) { + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: + sb.append("always : "); + sb.append(Long.toHexString(val & 0x00000000FFFFFFFF)); + break; + + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK: + sb.append("ask"); + break; + + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: + sb.append("never"); + break; + + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED: default: - case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED : return "undefined"; + sb.append("undefined"); + break; } + return sb.toString(); } @Override diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java index 92b8055..9b28401 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -38,6 +38,7 @@ public class PackageUserState { public ArraySet<String> enabledComponents; public int domainVerificationStatus; + public int appLinkGeneration; public PackageUserState() { installed = true; @@ -60,5 +61,6 @@ public class PackageUserState { ? new ArraySet<>(o.enabledComponents) : null; blockUninstall = o.blockUninstall; domainVerificationStatus = o.domainVerificationStatus; + appLinkGeneration = o.appLinkGeneration; } } diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java index 579634f..19921b5 100644 --- a/core/java/android/content/res/ColorStateList.java +++ b/core/java/android/content/res/ColorStateList.java @@ -603,7 +603,7 @@ public class ColorStateList implements Parcelable { * @hide only for resource preloading */ public ConstantState<ColorStateList> getConstantState() { - if (mFactory != null) { + if (mFactory == null) { mFactory = new ColorStateListFactory(this); } return mFactory; diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 9a99a46..731903c 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -1918,6 +1918,7 @@ public class Resources { other.mResId = mResId; other.mForce = mForce; other.mCount = mCount; + other.mHashCode = mHashCode; return other; } } diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java index e7deae8..30cdfd3 100644 --- a/core/java/android/hardware/SystemSensorManager.java +++ b/core/java/android/hardware/SystemSensorManager.java @@ -123,7 +123,10 @@ public class SystemSensorManager extends SensorManager { SensorEventQueue queue = mSensorListeners.get(listener); if (queue == null) { Looper looper = (handler != null) ? handler.getLooper() : mMainLooper; - queue = new SensorEventQueue(listener, looper, this); + final String fullClassName = listener.getClass().getEnclosingClass() != null ? + listener.getClass().getEnclosingClass().getName() : + listener.getClass().getName(); + queue = new SensorEventQueue(listener, looper, this, fullClassName); if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) { queue.dispose(); return false; @@ -166,12 +169,17 @@ public class SystemSensorManager extends SensorManager { protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) { if (sensor == null) throw new IllegalArgumentException("sensor cannot be null"); + if (listener == null) throw new IllegalArgumentException("listener cannot be null"); + if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false; synchronized (mTriggerListeners) { TriggerEventQueue queue = mTriggerListeners.get(listener); if (queue == null) { - queue = new TriggerEventQueue(listener, mMainLooper, this); + final String fullClassName = listener.getClass().getEnclosingClass() != null ? + listener.getClass().getEnclosingClass().getName() : + listener.getClass().getName(); + queue = new TriggerEventQueue(listener, mMainLooper, this, fullClassName); if (!queue.addSensor(sensor, 0, 0)) { queue.dispose(); return false; @@ -234,7 +242,8 @@ public class SystemSensorManager extends SensorManager { } // Initialize a client for data_injection. if (mInjectEventQueue == null) { - mInjectEventQueue = new InjectEventQueue(mMainLooper, this); + mInjectEventQueue = new InjectEventQueue(mMainLooper, this, + mContext.getPackageName()); } } else { // If data injection is being disabled clean up the native resources. @@ -296,10 +305,11 @@ public class SystemSensorManager extends SensorManager { protected static final int OPERATING_MODE_NORMAL = 0; protected static final int OPERATING_MODE_DATA_INJECTION = 1; - BaseEventQueue(Looper looper, SystemSensorManager manager, int mode) { + BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) { + if (packageName == null) packageName = ""; nSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance, new WeakReference<>(this), looper.getQueue(), mScratch, - manager.mContext.getPackageName(), mode, manager.mContext.getOpPackageName()); + packageName, mode, manager.mContext.getOpPackageName()); mCloseGuard.open("dispose"); mManager = manager; } @@ -419,8 +429,8 @@ public class SystemSensorManager extends SensorManager { private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>(); public SensorEventQueue(SensorEventListener listener, Looper looper, - SystemSensorManager manager) { - super(looper, manager, OPERATING_MODE_NORMAL); + SystemSensorManager manager, String packageName) { + super(looper, manager, OPERATING_MODE_NORMAL, packageName); mListener = listener; } @@ -486,8 +496,8 @@ public class SystemSensorManager extends SensorManager { private final SparseArray<TriggerEvent> mTriggerEvents = new SparseArray<TriggerEvent>(); public TriggerEventQueue(TriggerEventListener listener, Looper looper, - SystemSensorManager manager) { - super(looper, manager, OPERATING_MODE_NORMAL); + SystemSensorManager manager, String packageName) { + super(looper, manager, OPERATING_MODE_NORMAL, packageName); mListener = listener; } @@ -540,8 +550,8 @@ public class SystemSensorManager extends SensorManager { } final class InjectEventQueue extends BaseEventQueue { - public InjectEventQueue(Looper looper, SystemSensorManager manager) { - super(looper, manager, OPERATING_MODE_DATA_INJECTION); + public InjectEventQueue(Looper looper, SystemSensorManager manager, String packageName) { + super(looper, manager, OPERATING_MODE_DATA_INJECTION, packageName); } int injectSensorData(int handle, float[] values,int accuracy, long timestamp) { diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 30aa2d5..5583920 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -1901,7 +1901,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <tbody> * <tr> * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td> - * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td> + * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} (*1)</td> * <td align="center">Any</td> * <td align="center"></td> * </tr> @@ -1913,7 +1913,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * </tr> * <tr> * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td> - * <td align="center">1280x720 (720)</td> + * <td align="center">1280x720 (720p)</td> * <td align="center">Any</td> * <td align="center">if 720p <= activeArraySize</td> * </tr> @@ -1951,6 +1951,22 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * </table> * <p>Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} and {@link android.hardware.camera2.CameraDevice#createCaptureSession } for additional mandatory * stream configurations on a per-capability basis.</p> + * <p>*1: For JPEG format, the sizes may be restricted by below conditions:</p> + * <ul> + * <li>The HAL may choose the aspect ratio of each Jpeg size to be one of well known ones + * (e.g. 4:3, 16:9, 3:2 etc.). If the sensor maximum resolution + * (defined by {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}) has an aspect ratio other than these, + * it does not have to be included in the supported JPEG sizes.</li> + * <li>Some hardware JPEG encoders may have pixel boundary alignment requirements, such as + * the dimensions being a multiple of 16. + * Therefore, the maximum JPEG size may be smaller than sensor maximum resolution. + * However, the largest JPEG size will be as close as possible to the sensor maximum + * resolution given above constraints. It is required that after aspect ratio adjustments, + * additional size reduction due to other issues must be less than 3% in area. For example, + * if the sensor maximum resolution is 3280x2464, if the maximum JPEG size has aspect + * ratio 4:3, and the JPEG encoder alignment requirement is 16, the maximum JPEG size will be + * 3264x2448.</li> + * </ul> * <p>This key is available on all devices.</p> * * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 0fb6889..2e4f628 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -723,6 +723,8 @@ public final class CameraManager { private static final String TAG = "CameraManagerGlobal"; private final boolean DEBUG = false; + private final int CAMERA_SERVICE_RECONNECT_DELAY_MS = 1000; + // Singleton instance private static final CameraManagerGlobal gCameraManager = new CameraManagerGlobal(); @@ -1158,6 +1160,45 @@ public final class CameraManager { } /** + * Try to connect to camera service after some delay if any client registered camera + * availability callback or torch status callback. + */ + private void scheduleCameraServiceReconnectionLocked() { + final Handler handler; + + if (mCallbackMap.size() > 0) { + handler = mCallbackMap.valueAt(0); + } else if (mTorchCallbackMap.size() > 0) { + handler = mTorchCallbackMap.valueAt(0); + } else { + // Not necessary to reconnect camera service if no client registers a callback. + return; + } + + if (DEBUG) { + Log.v(TAG, "Reconnecting Camera Service in " + CAMERA_SERVICE_RECONNECT_DELAY_MS + + " ms"); + } + + handler.postDelayed( + new Runnable() { + @Override + public void run() { + ICameraService cameraService = getCameraService(); + if (cameraService == null) { + synchronized(mLock) { + if (DEBUG) { + Log.v(TAG, "Reconnecting Camera Service failed."); + } + scheduleCameraServiceReconnectionLocked(); + } + } + } + }, + CAMERA_SERVICE_RECONNECT_DELAY_MS); + } + + /** * Listener for camera service death. * * <p>The camera service isn't supposed to die under any normal circumstances, but can be @@ -1171,21 +1212,19 @@ public final class CameraManager { mCameraService = null; - // Tell listeners that the cameras and torch modes are _available_, because any - // existing clients will have gotten disconnected. This is optimistic under the - // assumption that the service will be back shortly. - // - // Without this, a camera service crash while a camera is open will never signal - // to listeners that previously in-use cameras are now available. + // Tell listeners that the cameras and torch modes are unavailable and schedule a + // reconnection to camera service. When camera service is reconnected, the camera + // and torch statuses will be updated. for (int i = 0; i < mDeviceStatus.size(); i++) { String cameraId = mDeviceStatus.keyAt(i); - onStatusChangedLocked(STATUS_PRESENT, cameraId); + onStatusChangedLocked(STATUS_NOT_PRESENT, cameraId); } for (int i = 0; i < mTorchStatus.size(); i++) { String cameraId = mTorchStatus.keyAt(i); - onTorchStatusChangedLocked(TORCH_STATUS_AVAILABLE_OFF, cameraId); + onTorchStatusChangedLocked(TORCH_STATUS_NOT_AVAILABLE, cameraId); } + scheduleCameraServiceReconnectionLocked(); } } diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index c8ae5d4..c36683b 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -1935,21 +1935,21 @@ public abstract class CameraMetadata<TKey> { /** * <p>Same as FACE_PRIORITY scene mode, except that the camera - * device will choose higher sensivity values ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}) + * device will choose higher sensitivity values ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}) * under low light conditions.</p> * <p>The camera device may be tuned to expose the images in a reduced * sensitivity range to produce the best quality images. For example, * if the {@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange} gives range of [100, 1600], * the camera device auto-exposure routine tuning process may limit the actual - * exposure sensivity range to [100, 1200] to ensure that the noise level isn't - * exessive to compromise the image quality. Under this situation, the image under + * exposure sensitivity range to [100, 1200] to ensure that the noise level isn't + * exessive in order to preserve the image quality. Under this situation, the image under * low light may be under-exposed when the sensor max exposure time (bounded by the * {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange} when {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is one of the - * ON_* modes) and effecitve max sensitivity are reached. This scene mode allows the + * ON_* modes) and effective max sensitivity are reached. This scene mode allows the * camera device auto-exposure routine to increase the sensitivity up to the max * sensitivity specified by {@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange} when the scene is too * dark and the max exposure time is reached. The captured images may be noisier - * compared with the images captured in normal FACE_PRIORITY mode, therefore, it is + * compared with the images captured in normal FACE_PRIORITY mode; therefore, it is * recommended that the application only use this scene mode when it is capable of * reducing the noise level of the captured images.</p> * <p>Unlike the other scene modes, {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}, diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl index 0fe112c..80c7b1a 100644 --- a/core/java/android/hardware/usb/IUsbManager.aidl +++ b/core/java/android/hardware/usb/IUsbManager.aidl @@ -19,6 +19,8 @@ package android.hardware.usb; import android.app.PendingIntent; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbPort; +import android.hardware.usb.UsbPortStatus; import android.os.Bundle; import android.os.ParcelFileDescriptor; @@ -108,4 +110,13 @@ interface IUsbManager /* Clear public keys installed for secure USB debugging */ void clearUsbDebuggingKeys(); + + /* Gets the list of USB ports. */ + UsbPort[] getPorts(); + + /* Gets the status of the specified USB port. */ + UsbPortStatus getPortStatus(in String portId); + + /* Sets the port's current role. */ + void setPortRoles(in String portId, int powerRole, int dataRole); } diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index f58b9d6..c88f213 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -17,6 +17,8 @@ package android.hardware.usb; +import com.android.internal.util.Preconditions; + import android.app.PendingIntent; import android.content.Context; import android.os.Bundle; @@ -74,6 +76,22 @@ public class UsbManager { public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE"; + /** + * Broadcast Action: A broadcast for USB port changes. + * + * This intent is sent when a USB port is added, removed, or changes state. + * <ul> + * <li> {@link #EXTRA_PORT} containing the {@link android.hardware.usb.UsbPort} + * for the port. + * <li> {@link #EXTRA_PORT_STATUS} containing the {@link android.hardware.usb.UsbPortStatus} + * for the port, or null if the port has been removed + * </ul> + * + * @hide + */ + public static final String ACTION_USB_PORT_CHANGED = + "android.hardware.usb.action.USB_PORT_CHANGED"; + /** * Broadcast Action: A broadcast for USB device attached event. * @@ -214,6 +232,23 @@ public class UsbManager { public static final String USB_FUNCTION_ACCESSORY = "accessory"; /** + * Name of extra for {@link #ACTION_USB_PORT_CHANGED} + * containing the {@link UsbPort} object for the port. + * + * @hide + */ + public static final String EXTRA_PORT = "port"; + + /** + * Name of extra for {@link #ACTION_USB_PORT_CHANGED} + * containing the {@link UsbPortStatus} object for the port, or null if the port + * was removed. + * + * @hide + */ + public static final String EXTRA_PORT_STATUS = "portStatus"; + + /** * Name of extra for {@link #ACTION_USB_DEVICE_ATTACHED} and * {@link #ACTION_USB_DEVICE_DETACHED} broadcasts * containing the {@link UsbDevice} object for the device. @@ -499,6 +534,77 @@ public class UsbManager { return false; } + /** + * Returns a list of physical USB ports on the device. + * <p> + * This list is guaranteed to contain all dual-role USB Type C ports but it might + * be missing other ports depending on whether the kernel USB drivers have been + * updated to publish all of the device's ports through the new "dual_role_usb" + * device class (which supports all types of ports despite its name). + * </p> + * + * @return The list of USB ports, or null if none. + * + * @hide + */ + public UsbPort[] getPorts() { + try { + return mService.getPorts(); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getPorts", e); + } + return null; + } + + /** + * Gets the status of the specified USB port. + * + * @param port The port to query. + * @return The status of the specified USB port, or null if unknown. + * + * @hide + */ + public UsbPortStatus getPortStatus(UsbPort port) { + Preconditions.checkNotNull(port, "port must not be null"); + + try { + return mService.getPortStatus(port.getId()); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getPortStatus", e); + } + return null; + } + + /** + * Sets the desired role combination of the port. + * <p> + * The supported role combinations depend on what is connected to the port and may be + * determined by consulting + * {@link UsbPortStatus#isRoleCombinationSupported UsbPortStatus.isRoleCombinationSupported}. + * </p><p> + * Note: This function is asynchronous and may fail silently without applying + * the requested changes. If this function does cause a status change to occur then + * a {@link #ACTION_USB_PORT_CHANGED} broadcast will be sent. + * </p> + * + * @param powerRole The desired power role: {@link UsbPort#POWER_ROLE_SOURCE} + * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role. + * @param dataRole The desired data role: {@link UsbPort#DATA_ROLE_HOST} + * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role. + * + * @hide + */ + public void setPortRoles(UsbPort port, int powerRole, int dataRole) { + Preconditions.checkNotNull(port, "port must not be null"); + UsbPort.checkRoles(powerRole, dataRole); + + try { + mService.setPortRoles(port.getId(), powerRole, dataRole); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in setPortRole", e); + } + } + /** @hide */ public static String addFunction(String functions, String function) { if ("none".equals(functions)) { diff --git a/core/java/android/hardware/usb/UsbPort.aidl b/core/java/android/hardware/usb/UsbPort.aidl new file mode 100644 index 0000000..b7a7920 --- /dev/null +++ b/core/java/android/hardware/usb/UsbPort.aidl @@ -0,0 +1,19 @@ +/* + * 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.hardware.usb; + +parcelable UsbPort; diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java new file mode 100644 index 0000000..c9a4e9b --- /dev/null +++ b/core/java/android/hardware/usb/UsbPort.java @@ -0,0 +1,238 @@ +/* + * 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.hardware.usb; + +import com.android.internal.util.Preconditions; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Represents a physical USB port and describes its characteristics. + * <p> + * This object is immutable. + * </p> + * + * @hide + */ +public final class UsbPort implements Parcelable { + private final String mId; + private final int mSupportedModes; + + /** + * Mode bit: This USB port can act as a downstream facing port (host). + * <p> + * Implies that the port supports the {@link #POWER_ROLE_SOURCE} and {@link #DATA_ROLE_HOST} + * combination of roles (and possibly others as well). + * </p> + */ + public static final int MODE_DFP = 1 << 0; + + /** + * Mode bit: This USB port can act as an upstream facing port (device). + * <p> + * Implies that the port supports the {@link #POWER_ROLE_SINK} and {@link #DATA_ROLE_DEVICE} + * combination of roles (and possibly others as well). + * </p> + */ + public static final int MODE_UFP = 1 << 1; + + /** + * Mode bit: This USB port can act either as an downstream facing port (host) or as + * an upstream facing port (device). + * <p> + * Implies that the port supports the {@link #POWER_ROLE_SOURCE} and {@link #DATA_ROLE_HOST} + * combination of roles and the {@link #POWER_ROLE_SINK} and {@link #DATA_ROLE_DEVICE} + * combination of roles (and possibly others as well). + * </p> + */ + public static final int MODE_DUAL = MODE_DFP | MODE_UFP; + + /** + * Power role: This USB port can act as a source (provide power). + */ + public static final int POWER_ROLE_SOURCE = 1; + + /** + * Power role: This USB port can act as a sink (receive power). + */ + public static final int POWER_ROLE_SINK = 2; + + /** + * Data role: This USB port can act as a host (access data services). + */ + public static final int DATA_ROLE_HOST = 1; + + /** + * Data role: This USB port can act as a device (offer data services). + */ + public static final int DATA_ROLE_DEVICE = 2; + + private static final int NUM_DATA_ROLES = 3; + + /** @hide */ + public UsbPort(String id, int supportedModes) { + mId = id; + mSupportedModes = supportedModes; + } + + /** + * Gets the unique id of the port. + * + * @return The unique id of the port; not intended for display. + */ + public String getId() { + return mId; + } + + /** + * Gets the supported modes of the port. + * <p> + * The actual mode of the port may vary depending on what is plugged into it. + * </p> + * + * @return The supported modes: one of {@link #MODE_DFP}, {@link #MODE_UFP}, or + * {@link #MODE_DUAL}. + */ + public int getSupportedModes() { + return mSupportedModes; + } + + /** + * Combines one power and one data role together into a unique value with + * exactly one bit set. This can be used to efficiently determine whether + * a combination of roles is supported by testing whether that bit is present + * in a bit-field. + * + * @param powerRole The desired power role: {@link UsbPort#POWER_ROLE_SOURCE} + * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role. + * @param dataRole The desired data role: {@link UsbPort#DATA_ROLE_HOST} + * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role. + * @hide + */ + public static int combineRolesAsBit(int powerRole, int dataRole) { + checkRoles(powerRole, dataRole); + final int index = powerRole * NUM_DATA_ROLES + dataRole; + return 1 << index; + } + + /** @hide */ + public static String modeToString(int mode) { + switch (mode) { + case 0: + return "none"; + case MODE_DFP: + return "dfp"; + case MODE_UFP: + return "ufp"; + case MODE_DUAL: + return "dual"; + default: + return Integer.toString(mode); + } + } + + /** @hide */ + public static String powerRoleToString(int role) { + switch (role) { + case 0: + return "no-power"; + case POWER_ROLE_SOURCE: + return "source"; + case POWER_ROLE_SINK: + return "sink"; + default: + return Integer.toString(role); + } + } + + /** @hide */ + public static String dataRoleToString(int role) { + switch (role) { + case 0: + return "no-data"; + case DATA_ROLE_HOST: + return "host"; + case DATA_ROLE_DEVICE: + return "device"; + default: + return Integer.toString(role); + } + } + + /** @hide */ + public static String roleCombinationsToString(int combo) { + StringBuilder result = new StringBuilder(); + result.append("["); + + boolean first = true; + while (combo != 0) { + final int index = Integer.numberOfTrailingZeros(combo); + combo &= ~(1 << index); + final int powerRole = index / NUM_DATA_ROLES; + final int dataRole = index % NUM_DATA_ROLES; + if (first) { + first = false; + } else { + result.append(", "); + } + result.append(powerRoleToString(powerRole)); + result.append(':'); + result.append(dataRoleToString(dataRole)); + } + + result.append("]"); + return result.toString(); + } + + /** @hide */ + public static void checkRoles(int powerRole, int dataRole) { + Preconditions.checkArgumentInRange(powerRole, 0, POWER_ROLE_SINK, "powerRole"); + Preconditions.checkArgumentInRange(dataRole, 0, DATA_ROLE_DEVICE, "dataRole"); + } + + @Override + public String toString() { + return "UsbPort{id=" + mId + ", supportedModes=" + modeToString(mSupportedModes) + "}"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mId); + dest.writeInt(mSupportedModes); + } + + public static final Parcelable.Creator<UsbPort> CREATOR = + new Parcelable.Creator<UsbPort>() { + @Override + public UsbPort createFromParcel(Parcel in) { + String id = in.readString(); + int supportedModes = in.readInt(); + return new UsbPort(id, supportedModes); + } + + @Override + public UsbPort[] newArray(int size) { + return new UsbPort[size]; + } + }; +} diff --git a/core/java/android/hardware/usb/UsbPortStatus.aidl b/core/java/android/hardware/usb/UsbPortStatus.aidl new file mode 100644 index 0000000..9a7e468 --- /dev/null +++ b/core/java/android/hardware/usb/UsbPortStatus.aidl @@ -0,0 +1,19 @@ +/* + * 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.hardware.usb; + +parcelable UsbPortStatus; diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java new file mode 100644 index 0000000..5c0e81a --- /dev/null +++ b/core/java/android/hardware/usb/UsbPortStatus.java @@ -0,0 +1,144 @@ +/* + * 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.hardware.usb; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Describes the status of a USB port. + * <p> + * This object is immutable. + * </p> + * + * @hide + */ +public final class UsbPortStatus implements Parcelable { + private final int mCurrentMode; + private final int mCurrentPowerRole; + private final int mCurrentDataRole; + private final int mSupportedRoleCombinations; + + /** @hide */ + public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole, + int supportedRoleCombinations) { + mCurrentMode = currentMode; + mCurrentPowerRole = currentPowerRole; + mCurrentDataRole = currentDataRole; + mSupportedRoleCombinations = supportedRoleCombinations; + } + + /** + * Returns true if there is anything connected to the port. + * + * @return True if there is anything connected to the port. + */ + public boolean isConnected() { + return mCurrentMode != 0; + } + + /** + * Gets the current mode of the port. + * + * @return The current mode: {@link UsbPort#MODE_DFP}, {@link UsbPort#MODE_UFP}, + * or 0 if nothing is connected. + */ + public int getCurrentMode() { + return mCurrentMode; + } + + /** + * Gets the current power role of the port. + * + * @return The current power role: {@link UsbPort#POWER_ROLE_SOURCE}, + * {@link UsbPort#POWER_ROLE_SINK}, or 0 if nothing is connected. + */ + public int getCurrentPowerRole() { + return mCurrentPowerRole; + } + + /** + * Gets the current data role of the port. + * + * @return The current data role: {@link UsbPort#DATA_ROLE_HOST}, + * {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if nothing is connected. + */ + public int getCurrentDataRole() { + return mCurrentDataRole; + } + + /** + * Returns true if the specified power and data role combination is supported + * given what is currently connected to the port. + * + * @param powerRole The power role to check: {@link UsbPort#POWER_ROLE_SOURCE} + * or {@link UsbPort#POWER_ROLE_SINK}, or 0 if no power role. + * @param dataRole The data role to check: either {@link UsbPort#DATA_ROLE_HOST} + * or {@link UsbPort#DATA_ROLE_DEVICE}, or 0 if no data role. + */ + public boolean isRoleCombinationSupported(int powerRole, int dataRole) { + return (mSupportedRoleCombinations & + UsbPort.combineRolesAsBit(powerRole, dataRole)) != 0; + } + + /** @hide */ + public int getSupportedRoleCombinations() { + return mSupportedRoleCombinations; + } + + @Override + public String toString() { + return "UsbPortStatus{connected=" + isConnected() + + ", currentMode=" + UsbPort.modeToString(mCurrentMode) + + ", currentPowerRole=" + UsbPort.powerRoleToString(mCurrentPowerRole) + + ", currentDataRole=" + UsbPort.dataRoleToString(mCurrentDataRole) + + ", supportedRoleCombinations=" + + UsbPort.roleCombinationsToString(mSupportedRoleCombinations) + + "}"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mCurrentMode); + dest.writeInt(mCurrentPowerRole); + dest.writeInt(mCurrentDataRole); + dest.writeInt(mSupportedRoleCombinations); + } + + public static final Parcelable.Creator<UsbPortStatus> CREATOR = + new Parcelable.Creator<UsbPortStatus>() { + @Override + public UsbPortStatus createFromParcel(Parcel in) { + int currentMode = in.readInt(); + int currentPowerRole = in.readInt(); + int currentDataRole = in.readInt(); + int supportedRoleCombinations = in.readInt(); + return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole, + supportedRoleCombinations); + } + + @Override + public UsbPortStatus[] newArray(int size) { + return new UsbPortStatus[size]; + } + }; +} diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java index 8bc2876..b039fc7 100644 --- a/core/java/android/inputmethodservice/ExtractEditText.java +++ b/core/java/android/inputmethodservice/ExtractEditText.java @@ -29,7 +29,7 @@ import android.widget.EditText; public class ExtractEditText extends EditText { private InputMethodService mIME; private int mSettingExtractedText; - + public ExtractEditText(Context context) { super(context, null); } @@ -45,11 +45,11 @@ public class ExtractEditText extends EditText { public ExtractEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } - + void setIME(InputMethodService ime) { mIME = ime; } - + /** * Start making changes that will not be reported to the client. That * is, {@link #onSelectionChanged(int, int)} will not result in sending @@ -58,7 +58,7 @@ public class ExtractEditText extends EditText { public void startInternalChanges() { mSettingExtractedText += 1; } - + /** * Finish making changes that will not be reported to the client. That * is, {@link #onSelectionChanged(int, int)} will not result in sending @@ -67,7 +67,7 @@ public class ExtractEditText extends EditText { public void finishInternalChanges() { mSettingExtractedText -= 1; } - + /** * Implement just to keep track of when we are setting text from the * client (vs. seeing changes in ourself from the user). @@ -80,7 +80,7 @@ public class ExtractEditText extends EditText { mSettingExtractedText--; } } - + /** * Report to the underlying text editor about selection changes. */ @@ -89,7 +89,7 @@ public class ExtractEditText extends EditText { mIME.onExtractedSelectionChanged(selStart, selEnd); } } - + /** * Redirect clicks to the IME for handling there. First allows any * on click handler to run, though. @@ -101,17 +101,18 @@ public class ExtractEditText extends EditText { } return false; } - + @Override public boolean onTextContextMenuItem(int id) { - if (mIME != null && mIME.onExtractTextContextMenuItem(id)) { + // Select all shouldn't be handled by the original edit text, but by the extracted one. + if (id != android.R.id.selectAll && mIME != null && mIME.onExtractTextContextMenuItem(id)) { // Mode was started on Extracted, needs to be stopped here. - // Cut and paste will change the text, which stops selection mode. - if (id == android.R.id.copy) stopTextActionMode(); + // Cut will change the text, which stops selection mode. + if (id == android.R.id.copy || id == android.R.id.paste) stopTextActionMode(); return true; } return super.onTextContextMenuItem(id); } - + /** * We are always considered to be an input method target. */ @@ -119,14 +120,14 @@ public class ExtractEditText extends EditText { public boolean isInputMethodTarget() { return true; } - + /** * Return true if the edit text is currently showing a scroll bar. */ public boolean hasVerticalScrollBar() { return computeVerticalScrollRange() > computeVerticalScrollExtent(); } - + /** * Pretend like the window this view is in always has focus, so its * highlight and cursor will be displayed. diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 78f8b95..46c28a6 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -112,7 +112,7 @@ interface IConnectivityManager void startLegacyVpn(in VpnProfile profile); - LegacyVpnInfo getLegacyVpnInfo(); + LegacyVpnInfo getLegacyVpnInfo(int userId); VpnInfo[] getAllVpnInfo(); diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index adc84bc..ecb7f5a 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -1193,9 +1193,13 @@ public abstract class BatteryStats implements Parcelable { public static final int EVENT_PACKAGE_INACTIVE = 0x000f; // Event for a package becoming active due to an interaction. public static final int EVENT_PACKAGE_ACTIVE = 0x0010; + // Event for a package being on the temporary whitelist. + public static final int EVENT_TEMP_WHITELIST = 0x0011; + // Event for the screen waking up. + public static final int EVENT_SCREEN_WAKE_UP = 0x0012; // Number of event types. - public static final int EVENT_COUNT = 0x0011; + public static final int EVENT_COUNT = 0x0013; // Mask to extract out only the type part of the event. public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH); @@ -1219,6 +1223,10 @@ public abstract class BatteryStats implements Parcelable { EVENT_USER_FOREGROUND | EVENT_FLAG_FINISH; public static final int EVENT_ALARM_START = EVENT_ALARM | EVENT_FLAG_START; public static final int EVENT_ALARM_FINISH = EVENT_ALARM | EVENT_FLAG_FINISH; + public static final int EVENT_TEMP_WHITELIST_START = + EVENT_TEMP_WHITELIST | EVENT_FLAG_START; + public static final int EVENT_TEMP_WHITELIST_FINISH = + EVENT_TEMP_WHITELIST | EVENT_FLAG_FINISH; // For CMD_EVENT. public int eventCode; @@ -1852,12 +1860,14 @@ public abstract class BatteryStats implements Parcelable { public static final String[] HISTORY_EVENT_NAMES = new String[] { "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn", - "active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active" + "active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active", "tmpwhitelist", + "screenwake", }; public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] { "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn", - "Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa" + "Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa", "Etw", + "Esw", }; /** diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl index fe4aa13..b768852 100644 --- a/core/java/android/os/IDeviceIdleController.aidl +++ b/core/java/android/os/IDeviceIdleController.aidl @@ -27,6 +27,7 @@ interface IDeviceIdleController { int[] getAppIdWhitelist(); int[] getAppIdTempWhitelist(); boolean isPowerSaveWhitelistApp(String name); - void addPowerSaveTempWhitelistApp(String name, long duration, int userId); + void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason); + long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason); void exitIdle(String reason); } diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index 804d3d0..0f37ac7 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -37,7 +37,7 @@ interface IPowerManager boolean isWakeLockLevelSupported(int level); void userActivity(long time, int event, int flags); - void wakeUp(long time); + void wakeUp(long time, String reason, String opPackageName); void goToSleep(long time, int reason, int flags); void nap(long time); boolean isInteractive(); diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 6ef1cd0..9a1a03e 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -658,7 +658,17 @@ public final class PowerManager { */ public void wakeUp(long time) { try { - mService.wakeUp(time); + mService.wakeUp(time, "wakeUp", mContext.getOpPackageName()); + } catch (RemoteException e) { + } + } + + /** + * @hide + */ + public void wakeUp(long time, String reason) { + try { + mService.wakeUp(time, reason, mContext.getOpPackageName()); } catch (RemoteException e) { } } diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java index 84a879c..c3b098b 100644 --- a/core/java/android/os/storage/IMountService.java +++ b/core/java/android/os/storage/IMountService.java @@ -758,13 +758,15 @@ public interface IMountService extends IInterface { return _result; } - public StorageVolume[] getVolumeList(int userId) throws RemoteException { + public StorageVolume[] getVolumeList(int uid, String packageName) + throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); StorageVolume[] _result; try { _data.writeInterfaceToken(DESCRIPTOR); - _data.writeInt(userId); + _data.writeInt(uid); + _data.writeString(packageName); mRemote.transact(Stub.TRANSACTION_getVolumeList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArray(StorageVolume.CREATOR); @@ -1177,21 +1179,6 @@ public interface IMountService extends IInterface { _data.recycle(); } } - - @Override - public void remountUid(int uid) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeInt(uid); - mRemote.transact(Stub.TRANSACTION_remountUid, _data, _reply, 0); - _reply.readException(); - } finally { - _reply.recycle(); - _data.recycle(); - } - } } private static final String DESCRIPTOR = "IMountService"; @@ -1307,8 +1294,6 @@ public interface IMountService extends IInterface { static final int TRANSACTION_benchmark = IBinder.FIRST_CALL_TRANSACTION + 59; static final int TRANSACTION_setDebugFlags = IBinder.FIRST_CALL_TRANSACTION + 60; - static final int TRANSACTION_remountUid = IBinder.FIRST_CALL_TRANSACTION + 61; - /** * Cast an IBinder object into an IMountService interface, generating a * proxy if needed. @@ -1622,8 +1607,9 @@ public interface IMountService extends IInterface { } case TRANSACTION_getVolumeList: { data.enforceInterface(DESCRIPTOR); - int userId = data.readInt(); - StorageVolume[] result = getVolumeList(userId); + int uid = data.readInt(); + String packageName = data.readString(); + StorageVolume[] result = getVolumeList(uid, packageName); reply.writeNoException(); reply.writeTypedArray(result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); return true; @@ -1862,13 +1848,6 @@ public interface IMountService extends IInterface { reply.writeNoException(); return true; } - case TRANSACTION_remountUid: { - data.enforceInterface(DESCRIPTOR); - int uid = data.readInt(); - remountUid(uid); - reply.writeNoException(); - return true; - } } return super.onTransact(code, data, reply, flags); } @@ -2080,11 +2059,11 @@ public interface IMountService extends IInterface { /** * Returns list of all mountable volumes. */ - public StorageVolume[] getVolumeList(int userId) throws RemoteException; + public StorageVolume[] getVolumeList(int uid, String packageName) throws RemoteException; /** * Gets the path on the filesystem for the ASEC container itself. - * + * * @param cid ASEC container ID * @return path to filesystem or {@code null} if it's not found * @throws RemoteException @@ -2178,6 +2157,4 @@ public interface IMountService extends IInterface { public String getPrimaryStorageUuid() throws RemoteException; public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) throws RemoteException; - - public void remountUid(int uid) throws RemoteException; } diff --git a/core/java/android/os/storage/MountServiceInternal.java b/core/java/android/os/storage/MountServiceInternal.java new file mode 100644 index 0000000..17aaef9 --- /dev/null +++ b/core/java/android/os/storage/MountServiceInternal.java @@ -0,0 +1,82 @@ +/* + * 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.os.storage; + +/** + * Mount service local interface. + * + * @hide Only for use within the system server. + */ +public abstract class MountServiceInternal { + + /** + * Policy that influences how external storage is mounted and reported. + */ + public interface ExternalStorageMountPolicy { + /** + * Gets the external storage mount mode for the given uid. + * + * @param uid The UID for which to determine mount mode. + * @param packageName The package in the UID for making the call. + * @return The mount mode. + * + * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_NONE + * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_DEFAULT + * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_READ + * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_WRITE + */ + public int getMountMode(int uid, String packageName); + + /** + * Gets whether external storage should be reported to the given UID. + * + * @param uid The UID for which to determine whether it has external storage. + * @param packageName The package in the UID for making the call. + * @return Weather to report external storage. + * @return True to report the state of external storage, false to + * report it as unmounted. + */ + public boolean hasExternalStorage(int uid, String packageName); + } + + /** + * Adds a policy for determining how external storage is mounted and reported. + * The mount mode is the most conservative result from querying all registered + * policies. Similarly, the reported state is the most conservative result from + * querying all registered policies. + * + * @param policy The policy to add. + */ + public abstract void addExternalStoragePolicy(ExternalStorageMountPolicy policy); + + /** + * Notify the mount service that the mount policy for a UID changed. + * @param uid The UID for which policy changed. + * @param packageName The package in the UID for making the call. + */ + public abstract void onExternalStoragePolicyChanged(int uid, String packageName); + + /** + * Gets the mount mode to use for a given UID as determined by consultin all + * policies. + * + * @param uid The UID for which to get mount mode. + * @param packageName The package in the UID for making the call. + * @return The mount mode. + */ + public abstract int getExternalStorageMountMode(int uid, String packageName); +} diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index f03e04e..b2cec60 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -20,6 +20,7 @@ import static android.net.TrafficStats.MB_IN_BYTES; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityThread; import android.content.ContentResolver; import android.content.Context; import android.content.pm.IPackageMoveObserver; @@ -816,17 +817,19 @@ public class StorageManager { /** {@hide} */ private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) { - File canonicalFile = null; try { - canonicalFile = file.getCanonicalFile(); + file = file.getCanonicalFile(); } catch (IOException ignored) { - canonicalFile = null; + return null; } for (StorageVolume volume : volumes) { - if (volume.getPathFile().equals(file)) { - return volume; + File volumeFile = volume.getPathFile(); + try { + volumeFile = volumeFile.getCanonicalFile(); + } catch (IOException ignored) { + continue; } - if (FileUtils.contains(volume.getPathFile(), canonicalFile)) { + if (FileUtils.contains(volumeFile, file)) { return volume; } } @@ -857,7 +860,24 @@ public class StorageManager { final IMountService mountService = IMountService.Stub.asInterface( ServiceManager.getService("mount")); try { - return mountService.getVolumeList(userId); + String packageName = ActivityThread.currentOpPackageName(); + if (packageName == null) { + // Package name can be null if the activity thread is running but the app + // hasn't bound yet. In this case we fall back to the first package in the + // current UID. This works for runtime permissions as permission state is + // per UID and permission realted app ops are updated for all UID packages. + String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid( + android.os.Process.myUid()); + if (packageNames == null || packageNames.length <= 0) { + return new StorageVolume[0]; + } + packageName = packageNames[0]; + } + final int uid = ActivityThread.getPackageManager().getPackageUid(packageName, userId); + if (uid <= 0) { + return new StorageVolume[0]; + } + return mountService.getVolumeList(uid, packageName); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -894,15 +914,6 @@ public class StorageManager { } /** {@hide} */ - public void remountUid(int uid) { - try { - mMountService.remountUid(uid); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - } - - /** {@hide} */ private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10; private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES; private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES; @@ -956,7 +967,7 @@ public class StorageManager { || vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isMountedReadable()) { final File internalPath = FileUtils.rewriteAfterRename(vol.getPath(), vol.getInternalPath(), path); - if (internalPath != null) { + if (internalPath != null && internalPath.exists()) { return internalPath; } } diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java index 32f7bc9..8d603a1 100644 --- a/core/java/android/os/storage/VolumeInfo.java +++ b/core/java/android/os/storage/VolumeInfo.java @@ -298,14 +298,14 @@ public class VolumeInfo implements Parcelable { } } - public StorageVolume buildStorageVolume(Context context, int userId) { + public StorageVolume buildStorageVolume(Context context, int userId, boolean reportUnmounted) { final StorageManager storage = context.getSystemService(StorageManager.class); final boolean removable; final boolean emulated; final boolean allowMassStorage = false; - final String envState = getEnvironmentForState(state); - + final String envState = reportUnmounted + ? Environment.MEDIA_UNMOUNTED : getEnvironmentForState(state); File userPath = getPathForUser(userId); if (userPath == null) { userPath = new File("/dev/null"); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 4e13758..fff355b 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -574,7 +574,22 @@ public final class Settings { */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_MANAGE_OVERLAY_PERMISSION = - "android.settings.MANAGE_OVERLAY_PERMISSION"; + "android.settings.action.MANAGE_OVERLAY_PERMISSION"; + + /** + * Activity Action: Show settings to toggle apps' capablity to + * to read/write system settings. + * <p> + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_MANAGE_WRITE_SETTINGS = + "android.settings.action.MANAGE_WRITE_SETTINGS"; /** * Activity Action: Show screen of details about a particular application. diff --git a/core/java/android/service/dreams/Sandman.java b/core/java/android/service/dreams/Sandman.java index 5f5b079..eeb340b 100644 --- a/core/java/android/service/dreams/Sandman.java +++ b/core/java/android/service/dreams/Sandman.java @@ -92,7 +92,8 @@ public final class Sandman { // be awake by the time this happens. Otherwise the dream may not start. PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - powerManager.wakeUp(SystemClock.uptimeMillis()); + powerManager.wakeUp(SystemClock.uptimeMillis(), + "android.service.dreams:DREAM"); } else { Slog.i(TAG, "Activating dream by user request."); } diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index 549c93e..479c9e2 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -37,7 +37,6 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Locale; - /** * Top-level service of the current global voice interactor, which is providing * support for hotwording, the back-end of a {@link android.app.VoiceInteractor}, etc. @@ -154,11 +153,39 @@ public class VoiceInteractionService extends Service { } /** + * Set contextual options you would always like to have disabled when a session + * is shown. The flags may be any combination of + * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and + * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT + * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}. + */ + public void setDisabledShowContext(int flags) { + try { + mSystemService.setDisabledShowContext(flags); + } catch (RemoteException e) { + } + } + + /** + * Return the value set by {@link #setDisabledShowContext}. + */ + public int getDisabledShowContext() { + try { + return mSystemService.getDisabledShowContext(); + } catch (RemoteException e) { + return 0; + } + } + + /** * Request that the associated {@link android.service.voice.VoiceInteractionSession} be * shown to the user, starting it if necessary. * @param args Arbitrary arguments that will be propagated to the session. * @param flags Indicates additional optional behavior that should be performed. May - * be {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} + * be any combination of + * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and + * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT + * VoiceInteractionSession.SHOW_WITH_SCREENSHOT} * to request that the system generate and deliver assist data on the current foreground * app as part of showing the session UI. */ diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index e408b36..95f96e8 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -650,7 +650,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback { @Override public void executeMessage(Message msg) { - SomeArgs args; + SomeArgs args = null; switch (msg.what) { case MSG_START_CONFIRMATION: if (DEBUG) Log.d(TAG, "onConfirm: req=" + msg.obj); @@ -676,6 +676,8 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall args = (SomeArgs)msg.obj; if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg1); args.arg1 = onGetSupportedCommands((String[]) args.arg1); + args.complete(); + args = null; break; case MSG_CANCEL: if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request)msg.obj)); @@ -723,6 +725,9 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall doHide(); break; } + if (args != null) { + args.recycle(); + } } @Override @@ -908,12 +913,38 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } /** + * Equivalent to {@link VoiceInteractionService#setDisabledShowContext + * VoiceInteractionService.setDisabledShowContext(int)}. + */ + public void setDisabledShowContext(int flags) { + try { + mSystemService.setDisabledShowContext(flags); + } catch (RemoteException e) { + } + } + + /** + * Equivalent to {@link VoiceInteractionService#getDisabledShowContext + * VoiceInteractionService.getDisabledShowContext}. + */ + public int getDisabledShowContext() { + try { + return mSystemService.getDisabledShowContext(); + } catch (RemoteException e) { + return 0; + } + } + + /** * Show the UI for this session. This asks the system to go through the process of showing * your UI, which will eventually culminate in {@link #onShow}. This is similar to calling * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}. * @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} + * be any combination of + * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and + * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT + * VoiceInteractionSession.SHOW_WITH_SCREENSHOT} * to request that the system generate and deliver assist data on the current foreground * app as part of showing the session UI. */ diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java index a55a08c..dc1d6f6 100644 --- a/core/java/android/text/Html.java +++ b/core/java/android/text/Html.java @@ -137,7 +137,12 @@ public class Html { } /** - * Returns an HTML representation of the provided Spanned text. + * Returns an HTML representation of the provided Spanned text. A best effort is + * made to add HTML tags corresponding to spans. Also note that HTML metacharacters + * (such as "<" and "&") within the input text are escaped. + * + * @param text input text to convert + * @return string containing input converted to HTML */ public static String toHtml(Spanned text) { StringBuilder out = new StringBuilder(); diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java index d114d32..5c5deb4 100644 --- a/core/java/android/text/SpannableStringInternal.java +++ b/core/java/android/text/SpannableStringInternal.java @@ -214,10 +214,6 @@ import java.lang.reflect.Array; Object ret1 = null; for (int i = 0; i < spanCount; i++) { - if (kind != null && !kind.isInstance(spans[i])) { - continue; - } - int spanStart = data[i * COLUMNS + START]; int spanEnd = data[i * COLUMNS + END]; @@ -237,6 +233,11 @@ import java.lang.reflect.Array; } } + // verify span class as late as possible, since it is expensive + if (kind != null && !kind.isInstance(spans[i])) { + continue; + } + if (count == 0) { ret1 = spans[i]; count++; diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java index 4862f01..39f66a5 100644 --- a/core/java/android/util/LocalLog.java +++ b/core/java/android/util/LocalLog.java @@ -55,6 +55,12 @@ public final class LocalLog { } } + public synchronized void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) { + for (int i = mLog.size() - 1; i >= 0; i--) { + pw.println(mLog.get(i)); + } + } + public static class ReadOnlyLocalLog { private final LocalLog mLog; ReadOnlyLocalLog(LocalLog log) { diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java index d1af9dc..e3ce6f2 100644 --- a/core/java/android/widget/AppSecurityPermissions.java +++ b/core/java/android/widget/AppSecurityPermissions.java @@ -61,8 +61,6 @@ import java.util.Set; */ public class AppSecurityPermissions { - public static final int WHICH_PERSONAL = 1<<0; - public static final int WHICH_DEVICE = 1<<1; public static final int WHICH_NEW = 1<<2; public static final int WHICH_ALL = 0xffff; @@ -75,7 +73,8 @@ public class AppSecurityPermissions { = new HashMap<String, MyPermissionGroupInfo>(); private final List<MyPermissionGroupInfo> mPermGroupsList = new ArrayList<MyPermissionGroupInfo>(); - private final PermissionGroupInfoComparator mPermGroupComparator = new PermissionGroupInfoComparator(); + private final PermissionGroupInfoComparator mPermGroupComparator = + new PermissionGroupInfoComparator(); private final PermissionInfoComparator mPermComparator = new PermissionInfoComparator(); private final List<MyPermissionInfo> mPermsList = new ArrayList<MyPermissionInfo>(); private final CharSequence mNewPermPrefix; @@ -85,8 +84,6 @@ public class AppSecurityPermissions { CharSequence mLabel; final ArrayList<MyPermissionInfo> mNewPermissions = new ArrayList<MyPermissionInfo>(); - final ArrayList<MyPermissionInfo> mPersonalPermissions = new ArrayList<MyPermissionInfo>(); - final ArrayList<MyPermissionInfo> mDevicePermissions = new ArrayList<MyPermissionInfo>(); final ArrayList<MyPermissionInfo> mAllPermissions = new ArrayList<MyPermissionInfo>(); MyPermissionGroupInfo(PermissionInfo perm) { @@ -352,13 +349,6 @@ public class AppSecurityPermissions { } for (int i=0; i<strList.length; i++) { String permName = strList[i]; - // If we are only looking at an existing app, then we only - // care about permissions that have actually been granted to it. - if (installedPkgInfo != null && info != installedPkgInfo) { - if ((flagsList[i]&PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0) { - continue; - } - } try { PermissionInfo tmpPermInfo = mPm.getPermissionInfo(permName, 0); if (tmpPermInfo == null) { @@ -431,10 +421,6 @@ public class AppSecurityPermissions { private List<MyPermissionInfo> getPermissionList(MyPermissionGroupInfo grp, int which) { if (which == WHICH_NEW) { return grp.mNewPermissions; - } else if (which == WHICH_PERSONAL) { - return grp.mPersonalPermissions; - } else if (which == WHICH_DEVICE) { - return grp.mDevicePermissions; } else { return grp.mAllPermissions; } @@ -577,15 +563,8 @@ public class AppSecurityPermissions { private static class PermissionGroupInfoComparator implements Comparator<MyPermissionGroupInfo> { private final Collator sCollator = Collator.getInstance(); - PermissionGroupInfoComparator() { - } + @Override public final int compare(MyPermissionGroupInfo a, MyPermissionGroupInfo b) { - if (((a.flags^b.flags)&PermissionGroupInfo.FLAG_PERSONAL_INFO) != 0) { - return ((a.flags&PermissionGroupInfo.FLAG_PERSONAL_INFO) != 0) ? -1 : 1; - } - if (a.priority != b.priority) { - return a.priority > b.priority ? -1 : 1; - } return sCollator.compare(a.mLabel, b.mLabel); } } @@ -628,11 +607,6 @@ public class AppSecurityPermissions { if (pInfo.mNew) { addPermToList(group.mNewPermissions, pInfo); } - if ((group.flags&PermissionGroupInfo.FLAG_PERSONAL_INFO) != 0) { - addPermToList(group.mPersonalPermissions, pInfo); - } else { - addPermToList(group.mDevicePermissions, pInfo); - } } } } @@ -652,12 +626,5 @@ public class AppSecurityPermissions { mPermGroupsList.add(pgrp); } Collections.sort(mPermGroupsList, mPermGroupComparator); - if (localLOGV) { - for (MyPermissionGroupInfo grp : mPermGroupsList) { - Log.i(TAG, "Group " + grp.name + " personal=" - + ((grp.flags&PermissionGroupInfo.FLAG_PERSONAL_INFO) != 0) - + " priority=" + grp.priority); - } - } } } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 96e033a..d897f49 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -16,6 +16,12 @@ package android.widget; +import java.text.BreakIterator; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + import android.R; import android.annotation.Nullable; import android.app.PendingIntent; @@ -106,12 +112,6 @@ import com.android.internal.util.GrowingArrayUtils; import com.android.internal.util.Preconditions; import com.android.internal.widget.EditableInputConnection; -import java.text.BreakIterator; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; - /** * Helper class used by TextView to handle editable text views. @@ -127,6 +127,7 @@ public class Editor { private static int DRAG_SHADOW_MAX_TEXT_LENGTH = 20; private static final float LINE_SLOP_MULTIPLIER_FOR_HANDLEVIEWS = 0.5f; private static final int UNSET_X_VALUE = -1; + private static final int UNSET_LINE = -1; // Tag used when the Editor maintains its own separate UndoManager. private static final String UNDO_OWNER_TAG = "Editor"; @@ -3510,7 +3511,11 @@ public class Editor { // Minimum touch target size for handles private int mMinSize; // Indicates the line of text that the handle is on. - protected int mPrevLine = -1; + protected int mPrevLine = UNSET_LINE; + // Indicates the line of text that the user was touching. This can differ from mPrevLine + // when selecting text when the handles jump to the end / start of words which may be on + // a different line. + protected int mPreviousLineTouched = UNSET_LINE; public HandleView(Drawable drawableLtr, Drawable drawableRtl) { super(mTextView.getContext()); @@ -3801,6 +3806,7 @@ public class Editor { mLastParentX = positionListener.getPositionX(); mLastParentY = positionListener.getPositionY(); mIsDragging = true; + mPreviousLineTouched = UNSET_LINE; break; } @@ -4015,8 +4021,12 @@ public class Editor { Layout layout = mTextView.getLayout(); int offset; if (layout != null) { - int currLine = getCurrentLineAdjustedForSlop(layout, mPrevLine, y); + if (mPreviousLineTouched == UNSET_LINE) { + mPreviousLineTouched = mTextView.getLineAtCoordinate(y); + } + int currLine = getCurrentLineAdjustedForSlop(layout, mPreviousLineTouched, y); offset = mTextView.getOffsetAtCoordinate(currLine, x); + mPreviousLineTouched = currLine; } else { offset = mTextView.getOffsetForPosition(x, y); } @@ -4092,9 +4102,13 @@ public class Editor { return; } + if (mPreviousLineTouched == UNSET_LINE) { + mPreviousLineTouched = mTextView.getLineAtCoordinate(y); + } + boolean positionCursor = false; final int selectionEnd = mTextView.getSelectionEnd(); - int currLine = getCurrentLineAdjustedForSlop(layout, mPrevLine, y); + int currLine = getCurrentLineAdjustedForSlop(layout, mPreviousLineTouched, y); int initialOffset = mTextView.getOffsetAtCoordinate(currLine, x); if (initialOffset >= selectionEnd) { @@ -4138,9 +4152,9 @@ public class Editor { } else { final float xDiff = x - mPrevX; if (atRtl) { - isExpanding = xDiff > 0 || currLine > mPrevLine; + isExpanding = xDiff > 0 || currLine > mPreviousLineTouched; } else { - isExpanding = xDiff < 0 || currLine < mPrevLine; + isExpanding = xDiff < 0 || currLine < mPreviousLineTouched; } } @@ -4204,6 +4218,7 @@ public class Editor { offset = getNextCursorOffset(selectionEnd, false); mTouchWordDelta = 0.0f; } + mPreviousLineTouched = currLine; positionAtCursorOffset(offset, false); } mPrevX = x; @@ -4218,8 +4233,9 @@ public class Editor { @Override public boolean onTouchEvent(MotionEvent event) { boolean superResult = super.onTouchEvent(event); - if (event.getActionMasked() == MotionEvent.ACTION_UP) { - // Reset the touch word offset when the user has lifted their finger. + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + // Reset the touch word offset and x value when the user + // re-engages the handle. mTouchWordDelta = 0.0f; mPrevX = UNSET_X_VALUE; } @@ -4280,9 +4296,13 @@ public class Editor { return; } + if (mPreviousLineTouched == UNSET_LINE) { + mPreviousLineTouched = mTextView.getLineAtCoordinate(y); + } + boolean positionCursor = false; final int selectionStart = mTextView.getSelectionStart(); - int currLine = getCurrentLineAdjustedForSlop(layout, mPrevLine, y); + int currLine = getCurrentLineAdjustedForSlop(layout, mPreviousLineTouched, y); int initialOffset = mTextView.getOffsetAtCoordinate(currLine, x); if (initialOffset <= selectionStart) { @@ -4326,9 +4346,9 @@ public class Editor { } else { final float xDiff = x - mPrevX; if (atRtl) { - isExpanding = xDiff < 0 || currLine < mPrevLine; + isExpanding = xDiff < 0 || currLine < mPreviousLineTouched; } else { - isExpanding = xDiff > 0 || currLine > mPrevLine; + isExpanding = xDiff > 0 || currLine > mPreviousLineTouched; } } @@ -4392,6 +4412,7 @@ public class Editor { offset = getNextCursorOffset(selectionStart, true); mTouchWordDelta = 0.0f; } + mPreviousLineTouched = currLine; positionAtCursorOffset(offset, false); } mPrevX = x; @@ -4406,8 +4427,9 @@ public class Editor { @Override public boolean onTouchEvent(MotionEvent event) { boolean superResult = super.onTouchEvent(event); - if (event.getActionMasked() == MotionEvent.ACTION_UP) { - // Reset the touch word offset when the user has lifted their finger. + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + // Reset the touch word offset and x value when the user + // re-engages the handle. mTouchWordDelta = 0.0f; mPrevX = UNSET_X_VALUE; } @@ -4416,10 +4438,16 @@ public class Editor { } private int getCurrentLineAdjustedForSlop(Layout layout, int prevLine, float y) { + final int trueLine = mTextView.getLineAtCoordinate(y); if (layout == null || prevLine > layout.getLineCount() || layout.getLineCount() <= 0 || prevLine < 0) { // Invalid parameters, just return whatever line is at y. - return mTextView.getLineAtCoordinate(y); + return trueLine; + } + + if (Math.abs(trueLine - prevLine) >= 2) { + // Only stick to lines if we're within a line of the previous selection. + return trueLine; } final float verticalOffset = mTextView.viewportToContentVerticalOffset(); diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index f45e750..e672fc3 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -62,7 +62,7 @@ import com.android.internal.R; * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related * setTypeface() methods control the typeface and style of label text, whereas the * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and - * the related seSwitchTypeface() methods control that of the thumb. + * the related setSwitchTypeface() methods control that of the thumb. * * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a> * guide.</p> diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 42ac599..131ba46 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -6347,17 +6347,28 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (text.text != null) { if (content == null) { setText(text.text, TextView.BufferType.EDITABLE); - } else if (text.partialStartOffset < 0) { - removeParcelableSpans(content, 0, content.length()); - content.replace(0, content.length(), text.text); } else { - final int N = content.length(); - int start = text.partialStartOffset; - if (start > N) start = N; - int end = text.partialEndOffset; - if (end > N) end = N; + int start = 0; + int end = content.length(); + + if (text.partialStartOffset >= 0) { + final int N = content.length(); + start = text.partialStartOffset; + if (start > N) start = N; + end = text.partialEndOffset; + if (end > N) end = N; + } + removeParcelableSpans(content, start, end); - content.replace(start, end, text.text); + if (TextUtils.equals(content.subSequence(start, end), text.text)) { + if (text.text instanceof Spanned) { + // OK to copy spans only. + TextUtils.copySpansFrom((Spanned) text.text, start, end, + Object.class, content, start); + } + } else { + content.replace(start, end, text.text); + } } } |
