diff options
Diffstat (limited to 'core/java/android')
21 files changed, 351 insertions, 134 deletions
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl index 8ab9ac3..474154b 100644 --- a/core/java/android/app/IUiAutomationConnection.aidl +++ b/core/java/android/app/IUiAutomationConnection.aidl @@ -38,10 +38,12 @@ interface IUiAutomationConnection { boolean injectInputEvent(in InputEvent event, boolean sync); boolean setRotation(int rotation); Bitmap takeScreenshot(int width, int height); - void shutdown(); boolean clearWindowContentFrameStats(int windowId); WindowContentFrameStats getWindowContentFrameStats(int windowId); void clearWindowAnimationFrameStats(); WindowAnimationFrameStats getWindowAnimationFrameStats(); void executeShellCommand(String command, in ParcelFileDescriptor fd); + + // Called from the system process. + oneway void shutdown(); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index b0d8541..fc71783 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1862,6 +1862,9 @@ public class Notification implements Parcelable } else { sb.append("null"); } + if (this.tickerText != null) { + sb.append(" tick"); + } sb.append(" defaults=0x"); sb.append(Integer.toHexString(this.defaults)); sb.append(" flags=0x"); diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java index 40126d6..ee0fc91 100644 --- a/core/java/android/app/assist/AssistStructure.java +++ b/core/java/android/app/assist/AssistStructure.java @@ -4,6 +4,7 @@ import android.app.Activity; import android.content.ComponentName; import android.graphics.Matrix; import android.graphics.Rect; +import android.os.BadParcelableException; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -31,8 +32,12 @@ public class AssistStructure implements Parcelable { static final String TAG = "AssistStructure"; static final boolean DEBUG_PARCEL = false; + static final boolean DEBUG_PARCEL_CHILDREN = false; static final boolean DEBUG_PARCEL_TREE = false; + static final int VALIDATE_WINDOW_TOKEN = 0x11111111; + static final int VALIDATE_VIEW_TOKEN = 0x22222222; + boolean mHaveData; ComponentName mActivityComponent; @@ -173,6 +178,26 @@ public class AssistStructure implements Parcelable { mCurViewStackEntry = entry; } + void writeView(ViewNode child, Parcel out, PooledStringWriter pwriter, int levelAdj) { + if (DEBUG_PARCEL) Log.d(TAG, "write view: at " + out.dataPosition() + + ", windows=" + mNumWrittenWindows + + ", views=" + mNumWrittenViews + + ", level=" + (mCurViewStackPos+levelAdj)); + out.writeInt(VALIDATE_VIEW_TOKEN); + int flags = child.writeSelfToParcel(out, pwriter, mTmpMatrix); + mNumWrittenViews++; + // If the child has children, push it on the stack to write them next. + if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) { + if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG, + "Preparing to write " + child.mChildren.length + + " children: @ #" + mNumWrittenViews + + ", level " + (mCurViewStackPos+levelAdj)); + out.writeInt(child.mChildren.length); + int pos = ++mCurViewStackPos; + pushViewStackEntry(child, pos); + } + } + boolean writeNextEntryToParcel(AssistStructure as, Parcel out, PooledStringWriter pwriter) { // Write next view node if appropriate. if (mCurViewStackEntry != null) { @@ -182,20 +207,7 @@ public class AssistStructure implements Parcelable { + mCurViewStackEntry.curChild + " in " + mCurViewStackEntry.node); ViewNode child = mCurViewStackEntry.node.mChildren[mCurViewStackEntry.curChild]; mCurViewStackEntry.curChild++; - if (DEBUG_PARCEL) Log.d(TAG, "write view: at " + out.dataPosition() - + ", windows=" + mNumWrittenWindows - + ", views=" + mNumWrittenViews); - out.writeInt(1); - int flags = child.writeSelfToParcel(out, pwriter, mTmpMatrix); - mNumWrittenViews++; - // If the child has children, push it on the stack to write them next. - if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) { - if (DEBUG_PARCEL_TREE) Log.d(TAG, "Preparing to write " - + child.mChildren.length + " children under " + child); - out.writeInt(child.mChildren.length); - int pos = ++mCurViewStackPos; - pushViewStackEntry(child, pos); - } + writeView(child, out, pwriter, 1); return true; } @@ -223,13 +235,13 @@ public class AssistStructure implements Parcelable { if (DEBUG_PARCEL) Log.d(TAG, "write window #" + pos + ": at " + out.dataPosition() + ", windows=" + mNumWrittenWindows + ", views=" + mNumWrittenViews); - out.writeInt(1); + out.writeInt(VALIDATE_WINDOW_TOKEN); win.writeSelfToParcel(out, pwriter, mTmpMatrix); mNumWrittenWindows++; ViewNode root = win.mRoot; mCurViewStackPos = 0; - if (DEBUG_PARCEL_TREE) Log.d(TAG, "Pushing initial root view " + root); - pushViewStackEntry(root, 0); + if (DEBUG_PARCEL_TREE) Log.d(TAG, "Writing initial root view " + root); + writeView(root, out, pwriter, 0); return true; } @@ -271,11 +283,16 @@ public class AssistStructure implements Parcelable { + ", views=" + mNumReadViews); } - Parcel readParcel() { + Parcel readParcel(int validateToken, int level) { if (DEBUG_PARCEL) Log.d(TAG, "readParcel: at " + mCurParcel.dataPosition() + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows - + ", views=" + mNumReadViews); - if (mCurParcel.readInt() != 0) { + + ", views=" + mNumReadViews + ", level=" + level); + int token = mCurParcel.readInt(); + if (token != 0) { + if (token != validateToken) { + throw new BadParcelableException("Got token " + Integer.toHexString(token) + + ", expected token " + Integer.toHexString(validateToken)); + } return mCurParcel; } // We have run out of partial data, need to read another batch. @@ -406,7 +423,7 @@ public class AssistStructure implements Parcelable { } WindowNode(ParcelTransferReader reader) { - Parcel in = reader.readParcel(); + Parcel in = reader.readParcel(VALIDATE_WINDOW_TOKEN, 0); reader.mNumReadWindows++; mX = in.readInt(); mY = in.readInt(); @@ -414,7 +431,7 @@ public class AssistStructure implements Parcelable { mHeight = in.readInt(); mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); mDisplayId = in.readInt(); - mRoot = new ViewNode(reader); + mRoot = new ViewNode(reader, 0); } void writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix) { @@ -548,8 +565,8 @@ public class AssistStructure implements Parcelable { ViewNode() { } - ViewNode(ParcelTransferReader reader) { - final Parcel in = reader.readParcel(); + ViewNode(ParcelTransferReader reader, int nestingLevel) { + final Parcel in = reader.readParcel(VALIDATE_VIEW_TOKEN, nestingLevel); reader.mNumReadViews++; final PooledStringReader preader = reader.mStringReader; mClassName = preader.readString(); @@ -604,9 +621,13 @@ public class AssistStructure implements Parcelable { } if ((flags&FLAGS_HAS_CHILDREN) != 0) { final int NCHILDREN = in.readInt(); + if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG, + "Preparing to read " + NCHILDREN + + " children: @ #" + reader.mNumReadViews + + ", level " + nestingLevel); mChildren = new ViewNode[NCHILDREN]; for (int i=0; i<NCHILDREN; i++) { - mChildren[i] = new ViewNode(reader); + mChildren[i] = new ViewNode(reader, nestingLevel + 1); } } } diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java index e09ab56..2ba8774 100644 --- a/core/java/android/bluetooth/le/BluetoothLeScanner.java +++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java @@ -79,6 +79,10 @@ public final class BluetoothLeScanner { * delivered through {@code callback}. * <p> * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. + * An app must hold + * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or + * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission + * in order to get results. * * @param callback Callback used to deliver scan results. * @throws IllegalArgumentException If {@code callback} is null. @@ -95,6 +99,10 @@ public final class BluetoothLeScanner { * Start Bluetooth LE scan. The scan results will be delivered through {@code callback}. * <p> * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. + * An app must hold + * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or + * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission + * in order to get results. * * @param filters {@link ScanFilter}s for finding exact BLE devices. * @param settings Settings for the scan. diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 3cc7684..ba9cf7c 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -16,8 +16,11 @@ package android.content; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.Manifest.permission.INTERACT_ACROSS_USERS; +import static android.app.AppOpsManager.MODE_ALLOWED; +import static android.app.AppOpsManager.MODE_ERRORED; +import static android.app.AppOpsManager.MODE_IGNORED; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import android.annotation.NonNull; import android.annotation.Nullable; @@ -40,8 +43,8 @@ import android.os.OperationCanceledException; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.UserHandle; -import android.util.Log; import android.text.TextUtils; +import android.util.Log; import java.io.File; import java.io.FileDescriptor; @@ -474,14 +477,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 { private int enforceReadPermission(String callingPkg, Uri uri, IBinder callerToken) throws SecurityException { - enforceReadPermissionInner(uri, callerToken); - - final int permOp = AppOpsManager.permissionToOpCode(mReadPermission); - if (permOp != AppOpsManager.OP_NONE) { - final int mode = mAppOpsManager.noteProxyOp(permOp, callingPkg); - if (mode != AppOpsManager.MODE_ALLOWED) { - return mode; - } + final int mode = enforceReadPermissionInner(uri, callingPkg, callerToken); + if (mode != MODE_ALLOWED) { + return mode; } if (mReadOp != AppOpsManager.OP_NONE) { @@ -493,14 +491,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 { private int enforceWritePermission(String callingPkg, Uri uri, IBinder callerToken) throws SecurityException { - enforceWritePermissionInner(uri, callerToken); - - final int permOp = AppOpsManager.permissionToOpCode(mWritePermission); - if (permOp != AppOpsManager.OP_NONE) { - final int mode = mAppOpsManager.noteProxyOp(permOp, callingPkg); - if (mode != AppOpsManager.MODE_ALLOWED) { - return mode; - } + final int mode = enforceWritePermissionInner(uri, callingPkg, callerToken); + if (mode != MODE_ALLOWED) { + return mode; } if (mWriteOp != AppOpsManager.OP_NONE) { @@ -518,26 +511,47 @@ public abstract class ContentProvider implements ComponentCallbacks2 { == PERMISSION_GRANTED; } + /** + * Verify that calling app holds both the given permission and any app-op + * associated with that permission. + */ + private int checkPermissionAndAppOp(String permission, String callingPkg, + IBinder callerToken) { + if (getContext().checkPermission(permission, Binder.getCallingPid(), Binder.getCallingUid(), + callerToken) != PERMISSION_GRANTED) { + return MODE_ERRORED; + } + + final int permOp = AppOpsManager.permissionToOpCode(permission); + if (permOp != AppOpsManager.OP_NONE) { + return mTransport.mAppOpsManager.noteProxyOp(permOp, callingPkg); + } + + return MODE_ALLOWED; + } + /** {@hide} */ - protected void enforceReadPermissionInner(Uri uri, IBinder callerToken) + protected int enforceReadPermissionInner(Uri uri, String callingPkg, IBinder callerToken) throws SecurityException { final Context context = getContext(); final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); String missingPerm = null; + int strongestMode = MODE_ALLOWED; if (UserHandle.isSameApp(uid, mMyUid)) { - return; + return MODE_ALLOWED; } if (mExported && checkUser(pid, uid, context)) { final String componentPerm = getReadPermission(); if (componentPerm != null) { - if (context.checkPermission(componentPerm, pid, uid, callerToken) - == PERMISSION_GRANTED) { - return; + final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, callerToken); + if (mode == MODE_ALLOWED) { + return MODE_ALLOWED; } else { missingPerm = componentPerm; + strongestMode = Math.max(strongestMode, mode); } } @@ -551,14 +565,15 @@ public abstract class ContentProvider implements ComponentCallbacks2 { for (PathPermission pp : pps) { final String pathPerm = pp.getReadPermission(); if (pathPerm != null && pp.match(path)) { - if (context.checkPermission(pathPerm, pid, uid, callerToken) - == PERMISSION_GRANTED) { - return; + final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, callerToken); + if (mode == MODE_ALLOWED) { + return MODE_ALLOWED; } else { // any denied <path-permission> means we lose // default <provider> access. allowDefaultRead = false; missingPerm = pathPerm; + strongestMode = Math.max(strongestMode, mode); } } } @@ -566,7 +581,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { // if we passed <path-permission> checks above, and no default // <provider> permission, then allow access. - if (allowDefaultRead) return; + if (allowDefaultRead) return MODE_ALLOWED; } // last chance, check against any uri grants @@ -575,7 +590,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 { ? maybeAddUserId(uri, callingUserId) : uri; if (context.checkUriPermission(userUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION, callerToken) == PERMISSION_GRANTED) { - return; + return MODE_ALLOWED; + } + + // If the worst denial we found above was ignored, then pass that + // ignored through; otherwise we assume it should be a real error below. + if (strongestMode == MODE_IGNORED) { + return MODE_IGNORED; } final String failReason = mExported @@ -587,25 +608,27 @@ public abstract class ContentProvider implements ComponentCallbacks2 { } /** {@hide} */ - protected void enforceWritePermissionInner(Uri uri, IBinder callerToken) + protected int enforceWritePermissionInner(Uri uri, String callingPkg, IBinder callerToken) throws SecurityException { final Context context = getContext(); final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); String missingPerm = null; + int strongestMode = MODE_ALLOWED; if (UserHandle.isSameApp(uid, mMyUid)) { - return; + return MODE_ALLOWED; } if (mExported && checkUser(pid, uid, context)) { final String componentPerm = getWritePermission(); if (componentPerm != null) { - if (context.checkPermission(componentPerm, pid, uid, callerToken) - == PERMISSION_GRANTED) { - return; + final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, callerToken); + if (mode == MODE_ALLOWED) { + return MODE_ALLOWED; } else { missingPerm = componentPerm; + strongestMode = Math.max(strongestMode, mode); } } @@ -619,14 +642,15 @@ public abstract class ContentProvider implements ComponentCallbacks2 { for (PathPermission pp : pps) { final String pathPerm = pp.getWritePermission(); if (pathPerm != null && pp.match(path)) { - if (context.checkPermission(pathPerm, pid, uid, callerToken) - == PERMISSION_GRANTED) { - return; + final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, callerToken); + if (mode == MODE_ALLOWED) { + return MODE_ALLOWED; } else { // any denied <path-permission> means we lose // default <provider> access. allowDefaultWrite = false; missingPerm = pathPerm; + strongestMode = Math.max(strongestMode, mode); } } } @@ -634,13 +658,19 @@ public abstract class ContentProvider implements ComponentCallbacks2 { // if we passed <path-permission> checks above, and no default // <provider> permission, then allow access. - if (allowDefaultWrite) return; + if (allowDefaultWrite) return MODE_ALLOWED; } // last chance, check against any uri grants if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, callerToken) == PERMISSION_GRANTED) { - return; + return MODE_ALLOWED; + } + + // If the worst denial we found above was ignored, then pass that + // ignored through; otherwise we assume it should be a real error below. + if (strongestMode == MODE_IGNORED) { + return MODE_IGNORED; } final String failReason = mExported diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index ceb610a..bc24d67 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -253,7 +253,7 @@ interface IPackageManager { List<PackageInfo> getPreferredPackages(int flags); - void resetPreferredActivities(int userId); + void resetApplicationPreferences(int userId); ResolveInfo getLastChosenActivity(in Intent intent, String resolvedType, int flags); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 6533bbc..cda5816 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1514,6 +1514,13 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device has biometric hardware to detect a fingerprint. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device supports portrait orientation * screens. For backwards compatibility, you can assume that if neither * this nor {@link #FEATURE_SCREEN_LANDSCAPE} is set then the device supports diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index dc8ff8f..ba63969 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -892,7 +892,6 @@ public class ConnectivityManager { * * @deprecated Deprecated in favor of the cleaner * {@link #requestNetwork(NetworkRequest, NetworkCallback)} API. - * @removed */ public int startUsingNetworkFeature(int networkType, String feature) { NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature); @@ -939,8 +938,7 @@ public class ConnectivityManager { * implementation+feature combination, except that the value {@code -1} * always indicates failure. * - * @deprecated Deprecated in favor of the cleaner {@link unregisterNetworkCallback} API. - * @removed + * @deprecated Deprecated in favor of the cleaner {@link #unregisterNetworkCallback} API. */ public int stopUsingNetworkFeature(int networkType, String feature) { NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature); @@ -1220,7 +1218,6 @@ public class ConnectivityManager { * @deprecated Deprecated in favor of the * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, * {@link #bindProcessToNetwork} and {@link Network#getSocketFactory} API. - * @removed */ public boolean requestRouteToHost(int networkType, int hostAddress) { return requestRouteToHostAddress(networkType, NetworkUtils.intToInetAddress(hostAddress)); @@ -1239,7 +1236,6 @@ public class ConnectivityManager { * @hide * @deprecated Deprecated in favor of the {@link #requestNetwork} and * {@link #bindProcessToNetwork} API. - * @removed */ public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { try { diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index cfd5bf1..c4de4a2 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -662,6 +662,17 @@ public final class LinkProperties implements Parcelable { } /** + * Returns true if this link or any of its stacked interfaces has an IPv4 address. + * + * @return {@code true} if there is an IPv4 address, {@code false} otherwise. + */ + private boolean hasIPv4AddressOnInterface(String iface) { + return (mIfaceName.equals(iface) && hasIPv4Address()) || + (iface != null && mStackedLinks.containsKey(iface) && + mStackedLinks.get(iface).hasIPv4Address()); + } + + /** * Returns true if this link has a global preferred IPv6 address. * * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise. @@ -792,7 +803,7 @@ public final class LinkProperties implements Parcelable { if (ip instanceof Inet4Address) { // For IPv4, it suffices for now to simply have any address. - return hasIPv4Address(); + return hasIPv4AddressOnInterface(bestRoute.getInterface()); } else if (ip instanceof Inet6Address) { if (ip.isLinkLocalAddress()) { // For now, just make sure link-local destinations have diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 864225a..af4c2bc 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -16,6 +16,7 @@ package android.os; +import android.annotation.NonNull; import android.provider.DocumentsContract.Document; import android.system.ErrnoException; import android.system.Os; @@ -69,6 +70,8 @@ public class FileUtils { /** Regular expression for safe filenames: no spaces or metacharacters */ private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+"); + private static final File[] EMPTY = new File[0]; + /** * Set owner and mode of of given {@link File}. * @@ -634,4 +637,13 @@ public class FileUtils { return new File(parent, name + "." + ext); } } + + public static @NonNull File[] listFilesOrEmpty(File dir) { + File[] res = dir.listFiles(); + if (res != null) { + return res; + } else { + return EMPTY; + } + } } diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl index b768852..d3eec1e 100644 --- a/core/java/android/os/IDeviceIdleController.aidl +++ b/core/java/android/os/IDeviceIdleController.aidl @@ -29,5 +29,6 @@ interface IDeviceIdleController { boolean isPowerSaveWhitelistApp(String name); void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason); long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason); + long addPowerSaveTempWhitelistAppForSms(String name, int userId, String reason); void exitIdle(String reason); } diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 6979bee..5a341fc 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -640,7 +640,7 @@ public abstract class DocumentsProvider extends ContentProvider { final Bundle out = new Bundle(); try { if (METHOD_CREATE_DOCUMENT.equals(method)) { - enforceWritePermissionInner(documentUri, null); + enforceWritePermissionInner(documentUri, getCallingPackage(), null); final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE); final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME); @@ -654,7 +654,7 @@ public abstract class DocumentsProvider extends ContentProvider { out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri); } else if (METHOD_RENAME_DOCUMENT.equals(method)) { - enforceWritePermissionInner(documentUri, null); + enforceWritePermissionInner(documentUri, getCallingPackage(), null); final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME); final String newDocumentId = renameDocument(documentId, displayName); @@ -678,7 +678,7 @@ public abstract class DocumentsProvider extends ContentProvider { } } else if (METHOD_DELETE_DOCUMENT.equals(method)) { - enforceWritePermissionInner(documentUri, null); + enforceWritePermissionInner(documentUri, getCallingPackage(), null); deleteDocument(documentId); // Document no longer exists, clean up any grants diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index fff355b..a79970c 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7578,14 +7578,6 @@ public final class Settings { public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled"; /** - * Global override to disable VoLTE (independent of user setting) - * <p> - * Type: int (1 for disable VoLTE, 0 to use user configuration) - * @hide - */ - public static final String VOLTE_FEATURE_DISABLED = "volte_feature_disabled"; - - /** * Whether user can enable/disable LTE as a preferred network. A carrier might control * this via gservices, OMA-DM, carrier app, etc. * <p> diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java index 1ee3827..10a994a 100644 --- a/core/java/android/text/Hyphenator.java +++ b/core/java/android/text/Hyphenator.java @@ -45,6 +45,8 @@ public class Hyphenator { @GuardedBy("sLock") final static HashMap<Locale, Hyphenator> sMap = new HashMap<Locale, Hyphenator>(); + final static Hyphenator sEmptyHyphenator = new Hyphenator(StaticLayout.nLoadHyphenator("")); + final private long mNativePtr; private Hyphenator(long nativePtr) { @@ -53,19 +55,19 @@ public class Hyphenator { public static long get(@Nullable Locale locale) { synchronized (sLock) { - if (sMap.containsKey(locale)) { - Hyphenator result = sMap.get(locale); - return (result == null) ? 0 : result.mNativePtr; + Hyphenator result = sMap.get(locale); + if (result != null) { + return result.mNativePtr; } // TODO: Convert this a proper locale-fallback system // Fall back to language-only, if available Locale languageOnlyLocale = new Locale(locale.getLanguage()); - if (sMap.containsKey(languageOnlyLocale)) { - Hyphenator result = sMap.get(languageOnlyLocale); + result = sMap.get(languageOnlyLocale); + if (result != null) { sMap.put(locale, result); - return (result == null) ? 0 : result.mNativePtr; + return result.mNativePtr; } // Fall back to script-only, if available @@ -75,16 +77,16 @@ public class Hyphenator { .setLanguage("und") .setScript(script) .build(); - if (sMap.containsKey(scriptOnlyLocale)) { - Hyphenator result = sMap.get(scriptOnlyLocale); + result = sMap.get(scriptOnlyLocale); + if (result != null) { sMap.put(locale, result); - return (result == null) ? 0 : result.mNativePtr; + return result.mNativePtr; } } - sMap.put(locale, null); // To remember we found nothing. + sMap.put(locale, sEmptyHyphenator); // To remember we found nothing. } - return 0; + return sEmptyHyphenator.mNativePtr; } private static Hyphenator loadHyphenator(String languageTag) { diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java index 39f66a5..a405dab 100644 --- a/core/java/android/util/LocalLog.java +++ b/core/java/android/util/LocalLog.java @@ -30,20 +30,32 @@ public final class LocalLog { private LinkedList<String> mLog; private int mMaxLines; private long mNow; + private final boolean mKeepFirst; public LocalLog(int maxLines) { mLog = new LinkedList<String>(); mMaxLines = maxLines; + mKeepFirst = false; + } + + public LocalLog(int maxLines, boolean keepFirst) { + mLog = new LinkedList<String>(); + mMaxLines = maxLines; + mKeepFirst = keepFirst; } public synchronized void log(String msg) { + mNow = System.currentTimeMillis(); + StringBuilder sb = new StringBuilder(); + Calendar c = Calendar.getInstance(); + c.setTimeInMillis(mNow); + sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); + logStraight(sb.toString() + " - " + msg); + } + + private synchronized void logStraight(String msg) { + if (mKeepFirst == false || mLog.size() < mMaxLines) mLog.add(msg); if (mMaxLines > 0) { - mNow = System.currentTimeMillis(); - StringBuilder sb = new StringBuilder(); - Calendar c = Calendar.getInstance(); - c.setTimeInMillis(mNow); - sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); - mLog.add(sb.toString() + " - " + msg); while (mLog.size() > mMaxLines) mLog.remove(); } } @@ -74,4 +86,13 @@ public final class LocalLog { public ReadOnlyLocalLog readOnlyLocalLog() { return new ReadOnlyLocalLog(this); } + + public synchronized void copyTo(LocalLog other, int lines) { + int end = mLog.size()-1; + int begin = end - lines; + if (begin < 0) begin = 0; + for (; begin < end; begin++) { + other.logStraight(mLog.get(begin)); + } + } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 9b1db57..c22c0ef 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -555,11 +555,6 @@ public final class ViewRootImpl implements ViewParent, mPendingContentInsets.set(mAttachInfo.mContentInsets); mPendingStableInsets.set(mAttachInfo.mStableInsets); mPendingVisibleInsets.set(0, 0, 0, 0); - try { - relayoutWindow(attrs, getHostVisibility(), false); - } catch (RemoteException e) { - if (DEBUG_LAYOUT) Log.e(TAG, "failed to relayoutWindow", e); - } if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow); if (res < WindowManagerGlobal.ADD_OKAY) { mAttachInfo.mRootView = null; diff --git a/core/java/android/view/inputmethod/InputMethodManagerInternal.java b/core/java/android/view/inputmethod/InputMethodManagerInternal.java new file mode 100644 index 0000000..c22127b --- /dev/null +++ b/core/java/android/view/inputmethod/InputMethodManagerInternal.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.inputmethod; + +/** + * Input method manager local system service interface. + * + * @hide Only for use within the system server. + */ +public interface InputMethodManagerInternal { + /** + * Called by the power manager to tell the input method manager whether it + * should start watching for wake events. + */ + public void setInteractive(boolean interactive); +} diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java index 0b18bb8..4737e9b 100644 --- a/core/java/android/webkit/WebChromeClient.java +++ b/core/java/android/webkit/WebChromeClient.java @@ -284,19 +284,13 @@ public class WebChromeClient { * currently set for that origin. The host application should invoke the * specified callback with the desired permission state. See * {@link GeolocationPermissions} for details. - * - * If this method isn't overridden, the callback is invoked with permission - * denied state. - * * @param origin The origin of the web content attempting to use the * Geolocation API. * @param callback The callback to use to set the permission state for the * origin. */ public void onGeolocationPermissionsShowPrompt(String origin, - GeolocationPermissions.Callback callback) { - callback.invoke(origin, false, false); - } + GeolocationPermissions.Callback callback) {} /** * Notify the host application that a request for Geolocation permissions, diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java index e3ce6f2..a12b15e 100644 --- a/core/java/android/widget/AppSecurityPermissions.java +++ b/core/java/android/widget/AppSecurityPermissions.java @@ -533,6 +533,12 @@ public class AppSecurityPermissions { int existingReqFlags) { final int base = pInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE; final boolean isNormal = (base == PermissionInfo.PROTECTION_NORMAL); + + // We do not show normal permissions in the UI. + if (isNormal) { + return false; + } + final boolean isDangerous = (base == PermissionInfo.PROTECTION_DANGEROUS) || ((pInfo.protectionLevel&PermissionInfo.PROTECTION_FLAG_PRE23) != 0); final boolean isRequired = @@ -546,7 +552,7 @@ public class AppSecurityPermissions { // Dangerous and normal permissions are always shown to the user if the permission // is required, or it was previously granted - if ((isNormal || isDangerous) && (isRequired || wasGranted || isGranted)) { + if (isDangerous && (isRequired || wasGranted || isGranted)) { return true; } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 15d13ae..010cb27 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -1004,7 +1004,8 @@ public class Editor { } if (!handled && mTextActionMode != null) { - if (touchPositionIsInSelection()) { + // TODO: Fix dragging in extracted mode. + if (touchPositionIsInSelection() && !mTextView.isInExtractedMode()) { // Start a drag final int start = mTextView.getSelectionStart(); final int end = mTextView.getSelectionEnd(); @@ -4059,9 +4060,17 @@ public class Editor { private float mPrevX; // Indicates if the handle has moved a boundary between LTR and RTL text. private boolean mLanguageDirectionChanged = false; + // Distance from edge of horizontally scrolling text view + // to use to switch to character mode. + private final float mTextViewEdgeSlop; + // Used to save text view location. + private final int[] mTextViewLocation = new int[2]; public SelectionStartHandleView(Drawable drawableLtr, Drawable drawableRtl) { super(drawableLtr, drawableRtl); + ViewConfiguration viewConfiguration = ViewConfiguration.get( + mTextView.getContext()); + mTextViewEdgeSlop = viewConfiguration.getScaledTouchSlop() * 4; } @Override @@ -4099,7 +4108,7 @@ public class Editor { if (layout == null) { // HandleView will deal appropriately in positionAtCursorOffset when // layout is null. - positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false); + positionAndAdjustForCrossingHandles(mTextView.getOffsetForPosition(x, y)); return; } @@ -4141,12 +4150,12 @@ public class Editor { // to the current position. mLanguageDirectionChanged = true; mTouchWordDelta = 0.0f; - positionAtCursorOffset(offset, false); + positionAndAdjustForCrossingHandles(offset); return; } else if (mLanguageDirectionChanged && !isLvlBoundary) { // We've just moved past the boundary so update the position. After this we can // figure out if the user is expanding or shrinking to go by word or character. - positionAtCursorOffset(offset, false); + positionAndAdjustForCrossingHandles(offset); mTouchWordDelta = 0.0f; mLanguageDirectionChanged = false; return; @@ -4159,6 +4168,21 @@ public class Editor { } } + if (mTextView.getHorizontallyScrolling()) { + if (positionNearEdgeOfScrollingView(x, atRtl) + && (mTextView.getScrollX() != 0) + && ((isExpanding && offset < selectionStart) || !isExpanding)) { + // If we're expanding ensure that the offset is smaller than the + // selection start, if the handle snapped to the word, the finger position + // may be out of sync and we don't want the selection to jump back. + mTouchWordDelta = 0.0f; + final int nextOffset = atRtl ? layout.getOffsetToRightOf(mPreviousOffset) + : layout.getOffsetToLeftOf(mPreviousOffset); + positionAndAdjustForCrossingHandles(nextOffset); + return; + } + } + if (isExpanding) { // User is increasing the selection. if (!mInWord || currLine < mPrevLine) { @@ -4214,17 +4238,22 @@ public class Editor { } if (positionCursor) { - // Handles can not cross and selection is at least one character. - if (offset >= selectionEnd) { - offset = getNextCursorOffset(selectionEnd, false); - mTouchWordDelta = 0.0f; - } mPreviousLineTouched = currLine; - positionAtCursorOffset(offset, false); + positionAndAdjustForCrossingHandles(offset); } mPrevX = x; } + private void positionAndAdjustForCrossingHandles(int offset) { + final int selectionEnd = mTextView.getSelectionEnd(); + if (offset >= selectionEnd) { + // Handles can not cross and selection is at least one character. + offset = getNextCursorOffset(selectionEnd, false); + mTouchWordDelta = 0.0f; + } + positionAtCursorOffset(offset, false); + } + @Override protected void positionAtCursorOffset(int offset, boolean parentScrolled) { super.positionAtCursorOffset(offset, parentScrolled); @@ -4242,6 +4271,20 @@ public class Editor { } return superResult; } + + private boolean positionNearEdgeOfScrollingView(float x, boolean atRtl) { + mTextView.getLocationOnScreen(mTextViewLocation); + boolean nearEdge; + if (atRtl) { + int rightEdge = mTextViewLocation[0] + mTextView.getWidth() + - mTextView.getPaddingRight(); + nearEdge = x > rightEdge - mTextViewEdgeSlop; + } else { + int leftEdge = mTextViewLocation[0] + mTextView.getPaddingLeft(); + nearEdge = x < leftEdge + mTextViewEdgeSlop; + } + return nearEdge; + } } private class SelectionEndHandleView extends HandleView { @@ -4253,9 +4296,17 @@ public class Editor { private float mPrevX; // Indicates if the handle has moved a boundary between LTR and RTL text. private boolean mLanguageDirectionChanged = false; + // Distance from edge of horizontally scrolling text view + // to use to switch to character mode. + private final float mTextViewEdgeSlop; + // Used to save the text view location. + private final int[] mTextViewLocation = new int[2]; public SelectionEndHandleView(Drawable drawableLtr, Drawable drawableRtl) { super(drawableLtr, drawableRtl); + ViewConfiguration viewConfiguration = ViewConfiguration.get( + mTextView.getContext()); + mTextViewEdgeSlop = viewConfiguration.getScaledTouchSlop() * 4; } @Override @@ -4293,7 +4344,7 @@ public class Editor { if (layout == null) { // HandleView will deal appropriately in positionAtCursorOffset when // layout is null. - positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false); + positionAndAdjustForCrossingHandles(mTextView.getOffsetForPosition(x, y)); return; } @@ -4335,12 +4386,12 @@ public class Editor { // to the current position. mLanguageDirectionChanged = true; mTouchWordDelta = 0.0f; - positionAtCursorOffset(offset, false); + positionAndAdjustForCrossingHandles(offset); return; } else if (mLanguageDirectionChanged && !isLvlBoundary) { // We've just moved past the boundary so update the position. After this we can // figure out if the user is expanding or shrinking to go by word or character. - positionAtCursorOffset(offset, false); + positionAndAdjustForCrossingHandles(offset); mTouchWordDelta = 0.0f; mLanguageDirectionChanged = false; return; @@ -4353,6 +4404,21 @@ public class Editor { } } + if (mTextView.getHorizontallyScrolling()) { + if (positionNearEdgeOfScrollingView(x, atRtl) + && mTextView.canScrollHorizontally(atRtl ? -1 : 1) + && ((isExpanding && offset > selectionEnd) || !isExpanding)) { + // If we're expanding ensure that the offset is actually greater than the + // selection end, if the handle snapped to the word, the finger position + // may be out of sync and we don't want the selection to jump back. + mTouchWordDelta = 0.0f; + final int nextOffset = atRtl ? layout.getOffsetToLeftOf(mPreviousOffset) + : layout.getOffsetToRightOf(mPreviousOffset); + positionAndAdjustForCrossingHandles(nextOffset); + return; + } + } + if (isExpanding) { // User is increasing the selection. if (!mInWord || currLine > mPrevLine) { @@ -4408,17 +4474,22 @@ public class Editor { } if (positionCursor) { - // Handles can not cross and selection is at least one character. - if (offset <= selectionStart) { - offset = getNextCursorOffset(selectionStart, true); - mTouchWordDelta = 0.0f; - } mPreviousLineTouched = currLine; - positionAtCursorOffset(offset, false); + positionAndAdjustForCrossingHandles(offset); } mPrevX = x; } + private void positionAndAdjustForCrossingHandles(int offset) { + final int selectionStart = mTextView.getSelectionStart(); + if (offset <= selectionStart) { + // Handles can not cross and selection is at least one character. + offset = getNextCursorOffset(selectionStart, true); + mTouchWordDelta = 0.0f; + } + positionAtCursorOffset(offset, false); + } + @Override protected void positionAtCursorOffset(int offset, boolean parentScrolled) { super.positionAtCursorOffset(offset, parentScrolled); @@ -4436,6 +4507,20 @@ public class Editor { } return superResult; } + + private boolean positionNearEdgeOfScrollingView(float x, boolean atRtl) { + mTextView.getLocationOnScreen(mTextViewLocation); + boolean nearEdge; + if (atRtl) { + int leftEdge = mTextViewLocation[0] + mTextView.getPaddingLeft(); + nearEdge = x < leftEdge + mTextViewEdgeSlop; + } else { + int rightEdge = mTextViewLocation[0] + mTextView.getWidth() + - mTextView.getPaddingRight(); + nearEdge = x > rightEdge - mTextViewEdgeSlop; + } + return nearEdge; + } } private int getCurrentLineAdjustedForSlop(Layout layout, int prevLine, float y) { diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index dac02fa..6a561e6 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -731,7 +731,8 @@ public class RelativeLayout extends ViewGroup { // Negative values in a mySize value in RelativeLayout // measurement is code for, "we got an unspecified mode in the // RelativeLayout's measure spec." - if (mySize < 0 && !mAllowBrokenMeasureSpecs) { + final boolean isUnspecified = mySize < 0; + if (isUnspecified && !mAllowBrokenMeasureSpecs) { if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) { // Constraints fixed both edges, so child has an exact size. childSpecSize = Math.max(0, childEnd - childStart); @@ -767,7 +768,7 @@ public class RelativeLayout extends ViewGroup { if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) { // Constraints fixed both edges, so child must be an exact size. - childSpecMode = MeasureSpec.EXACTLY; + childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY; childSpecSize = Math.max(0, maxAvailable); } else { if (childSize >= 0) { @@ -784,7 +785,7 @@ public class RelativeLayout extends ViewGroup { } else if (childSize == LayoutParams.MATCH_PARENT) { // Child wanted to be as big as possible. Give all available // space. - childSpecMode = MeasureSpec.EXACTLY; + childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY; childSpecSize = Math.max(0, maxAvailable); } else if (childSize == LayoutParams.WRAP_CONTENT) { // Child wants to wrap content. Use AT_MOST to communicate |
