diff options
Diffstat (limited to 'core/java')
27 files changed, 576 insertions, 205 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 diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index cbe535f..91ae27b 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -27,7 +27,20 @@ import android.view.View; */ public class MetricsLogger implements MetricsConstants { // Temporary constants go here, to await migration to MetricsConstants. - // next value is 227; + // next value is 238; + + public static final int TUNER = 227; + public static final int TUNER_QS = 228; + public static final int TUNER_DEMO_MODE = 229; + + public static final int TUNER_QS_REORDER = 230; + public static final int TUNER_QS_ADD = 231; + public static final int TUNER_QS_REMOVE = 232; + public static final int TUNER_STATUS_BAR_ENABLE = 233; + public static final int TUNER_STATUS_BAR_DISABLE = 234; + public static final int TUNER_DEMO_MODE_ENABLED = 235; + public static final int TUNER_DEMO_MODE_ON = 236; + public static final int TUNER_BATTERY_PERCENTAGE = 237; public static void visible(Context context, int category) throws IllegalArgumentException { if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) { diff --git a/core/java/com/android/internal/midi/MidiConstants.java b/core/java/com/android/internal/midi/MidiConstants.java index c13e5fc..b6b8bf0 100644 --- a/core/java/com/android/internal/midi/MidiConstants.java +++ b/core/java/com/android/internal/midi/MidiConstants.java @@ -55,18 +55,30 @@ public final class MidiConstants { public final static int SYSTEM_BYTE_LENGTHS[] = { 1, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; - /********************************************************************/ - public static int getBytesPerMessage(int command) { - if ((command < 0x80) || (command > 0xFF)) { - return 0; - } else if (command >= 0xF0) { - return SYSTEM_BYTE_LENGTHS[command & 0x0F]; + /** + * MIDI messages, except for SysEx, are 1,2 or 3 bytes long. + * You can tell how long a MIDI message is from the first status byte. + * Do not call this for SysEx, which has variable length. + * @param statusByte + * @return number of bytes in a complete message or zero if data byte passed + */ + public static int getBytesPerMessage(byte statusByte) { + // Java bytes are signed so we need to mask off the high bits + // to get a value between 0 and 255. + int statusInt = statusByte & 0xFF; + if (statusInt >= 0xF0) { + // System messages use low nibble for size. + return SYSTEM_BYTE_LENGTHS[statusInt & 0x0F]; + } else if(statusInt >= 0x80) { + // Channel voice messages use high nibble for size. + return CHANNEL_BYTE_LENGTHS[(statusInt >> 4) - 8]; } else { - return CHANNEL_BYTE_LENGTHS[(command >> 4) - 8]; + return 0; // data byte } } + /** * @param msg * @param offset diff --git a/core/java/com/android/internal/midi/MidiFramer.java b/core/java/com/android/internal/midi/MidiFramer.java index 058f57c..62517fa 100644 --- a/core/java/com/android/internal/midi/MidiFramer.java +++ b/core/java/com/android/internal/midi/MidiFramer.java @@ -17,7 +17,7 @@ package com.android.internal.midi; import android.media.midi.MidiReceiver; -import android.util.Log; +//import android.util.Log; import java.io.IOException; @@ -37,7 +37,7 @@ public class MidiFramer extends MidiReceiver { private MidiReceiver mReceiver; private byte[] mBuffer = new byte[3]; private int mCount; - private int mRunningStatus; + private byte mRunningStatus; private int mNeeded; private boolean mInSysEx; @@ -59,22 +59,22 @@ public class MidiFramer extends MidiReceiver { @Override public void onSend(byte[] data, int offset, int count, long timestamp) throws IOException { - // Log.i(TAG, formatMidiData(data, offset, count)); int sysExStartOffset = (mInSysEx ? offset : -1); for (int i = 0; i < count; i++) { - int b = data[offset] & 0xFF; - if (b >= 0x80) { // status byte? - if (b < 0xF0) { // channel message? - mRunningStatus = (byte) b; + final byte currentByte = data[offset]; + final int currentInt = currentByte & 0xFF; + if (currentInt >= 0x80) { // status byte? + if (currentInt < 0xF0) { // channel message? + mRunningStatus = currentByte; mCount = 1; - mNeeded = MidiConstants.getBytesPerMessage(b) - 1; - } else if (b < 0xF8) { // system common? - if (b == 0xF0 /* SysEx Start */) { + mNeeded = MidiConstants.getBytesPerMessage(currentByte) - 1; + } else if (currentInt < 0xF8) { // system common? + if (currentInt == 0xF0 /* SysEx Start */) { // Log.i(TAG, "SysEx Start"); mInSysEx = true; sysExStartOffset = offset; - } else if (b == 0xF7 /* SysEx End */) { + } else if (currentInt == 0xF7 /* SysEx End */) { // Log.i(TAG, "SysEx End"); if (mInSysEx) { mReceiver.send(data, sysExStartOffset, @@ -83,10 +83,10 @@ public class MidiFramer extends MidiReceiver { sysExStartOffset = -1; } } else { - mBuffer[0] = (byte) b; + mBuffer[0] = currentByte; mRunningStatus = 0; mCount = 1; - mNeeded = MidiConstants.getBytesPerMessage(b) - 1; + mNeeded = MidiConstants.getBytesPerMessage(currentByte) - 1; } } else { // real-time? // Single byte message interleaved with other data. @@ -98,12 +98,11 @@ public class MidiFramer extends MidiReceiver { mReceiver.send(data, offset, 1, timestamp); } } else { // data byte - // Save SysEx data for SysEx End marker or end of buffer. if (!mInSysEx) { - mBuffer[mCount++] = (byte) b; + mBuffer[mCount++] = currentByte; if (--mNeeded == 0) { if (mRunningStatus != 0) { - mBuffer[0] = (byte) mRunningStatus; + mBuffer[0] = mRunningStatus; } mReceiver.send(mBuffer, 0, mCount, timestamp); mNeeded = MidiConstants.getBytesPerMessage(mBuffer[0]) - 1; diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java index 264b8c1..9caf78a 100644 --- a/core/java/com/android/internal/os/BatteryStatsHelper.java +++ b/core/java/com/android/internal/os/BatteryStatsHelper.java @@ -47,6 +47,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Locale; /** * A helper class for retrieving the power usage information for all applications and services. @@ -267,15 +268,20 @@ public final class BatteryStatsHelper { public static String makemAh(double power) { if (power == 0) return "0"; - else if (power < .00001) return String.format("%.8f", power); - else if (power < .0001) return String.format("%.7f", power); - else if (power < .001) return String.format("%.6f", power); - else if (power < .01) return String.format("%.5f", power); - else if (power < .1) return String.format("%.4f", power); - else if (power < 1) return String.format("%.3f", power); - else if (power < 10) return String.format("%.2f", power); - else if (power < 100) return String.format("%.1f", power); - else return String.format("%.0f", power); + + final String format; + if (power < .00001) format = "%.8f"; + else if (power < .0001) format = "%.7f"; + else if (power < .001) format = "%.6f"; + else if (power < .01) format = "%.5f"; + else if (power < .1) format = "%.4f"; + else if (power < 1) format = "%.3f"; + else if (power < 10) format = "%.2f"; + else if (power < 100) format = "%.1f"; + else format = "%.0f"; + + // Use English locale because this is never used in UI (only in checkin and dump). + return String.format(Locale.ENGLISH, format, power); } /** diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 60f47d6..e7c58f4 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -2560,14 +2560,24 @@ public final class BatteryStatsImpl extends BatteryStats { addHistoryEventLocked(elapsedRealtime, uptime, code, name, uid); } + boolean ensureStartClockTime(final long currentTime) { + final long ABOUT_ONE_YEAR = 365*24*60*60*1000L; + if (currentTime > ABOUT_ONE_YEAR && mStartClockTime < (currentTime-ABOUT_ONE_YEAR)) { + // If the start clock time has changed by more than a year, then presumably + // the previous time was completely bogus. So we are going to figure out a + // new time based on how much time has elapsed since we started counting. + mStartClockTime = currentTime - (SystemClock.elapsedRealtime()-(mRealtimeStart/1000)); + return true; + } + return false; + } + public void noteCurrentTimeChangedLocked() { final long currentTime = System.currentTimeMillis(); final long elapsedRealtime = SystemClock.elapsedRealtime(); final long uptime = SystemClock.uptimeMillis(); recordCurrentTimeChangeLocked(currentTime, elapsedRealtime, uptime); - if (isStartClockTimeValid()) { - mStartClockTime = currentTime; - } + ensureStartClockTime(currentTime); } public void noteProcessStartLocked(String name, int uid) { @@ -4306,19 +4316,11 @@ public final class BatteryStatsImpl extends BatteryStats { } } - boolean isStartClockTimeValid() { - return mStartClockTime > 365*24*60*60*1000L; - } - @Override public long getStartClockTime() { - if (!isStartClockTimeValid()) { - // If the last clock time we got was very small, then we hadn't had a real - // time yet, so try to get it again. - mStartClockTime = System.currentTimeMillis(); - if (isStartClockTimeValid()) { - recordCurrentTimeChangeLocked(mStartClockTime, SystemClock.elapsedRealtime(), - SystemClock.uptimeMillis()); - } + final long currentTime = System.currentTimeMillis(); + if (ensureStartClockTime(currentTime)) { + recordCurrentTimeChangeLocked(currentTime, SystemClock.elapsedRealtime(), + SystemClock.uptimeMillis()); } return mStartClockTime; } diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index 444f878..a709bb8 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -23,10 +23,10 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; +import android.graphics.CanvasProperty; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; -import android.graphics.RectF; import android.media.AudioManager; import android.os.Bundle; import android.os.Debug; @@ -38,8 +38,10 @@ import android.provider.Settings; import android.util.AttributeSet; import android.util.IntArray; import android.util.Log; +import android.view.DisplayListCanvas; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; +import android.view.RenderNodeAnimator; import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -200,10 +202,16 @@ public class LockPatternView extends View { } public static class CellState { - public float scale = 1.0f; - public float translateY = 0.0f; - public float alpha = 1.0f; - public float size; + int row; + int col; + boolean hwAnimating; + CanvasProperty<Float> hwRadius; + CanvasProperty<Float> hwCenterX; + CanvasProperty<Float> hwCenterY; + CanvasProperty<Paint> hwPaint; + float radius; + float translationY; + float alpha = 1f; public float lineEndX = Float.MIN_VALUE; public float lineEndY = Float.MIN_VALUE; public ValueAnimator lineAnimator; @@ -313,7 +321,9 @@ public class LockPatternView extends View { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { mCellStates[i][j] = new CellState(); - mCellStates[i][j].size = mDotSize; + mCellStates[i][j].radius = mDotSize/2; + mCellStates[i][j].row = i; + mCellStates[i][j].col = j; } } @@ -412,6 +422,112 @@ public class LockPatternView extends View { invalidate(); } + public void startCellStateAnimation(CellState cellState, float startAlpha, float endAlpha, + float startTranslationY, float endTranslationY, float startScale, float endScale, + long delay, long duration, + Interpolator interpolator, Runnable finishRunnable) { + if (isHardwareAccelerated()) { + startCellStateAnimationHw(cellState, startAlpha, endAlpha, startTranslationY, + endTranslationY, startScale, endScale, delay, duration, interpolator, + finishRunnable); + } else { + startCellStateAnimationSw(cellState, startAlpha, endAlpha, startTranslationY, + endTranslationY, startScale, endScale, delay, duration, interpolator, + finishRunnable); + } + } + + private void startCellStateAnimationSw(final CellState cellState, + final float startAlpha, final float endAlpha, + final float startTranslationY, final float endTranslationY, + final float startScale, final float endScale, + long delay, long duration, Interpolator interpolator, final Runnable finishRunnable) { + cellState.alpha = startAlpha; + cellState.translationY = startTranslationY; + cellState.radius = mDotSize/2 * startScale; + ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f); + animator.setDuration(duration); + animator.setStartDelay(delay); + animator.setInterpolator(interpolator); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float t = (float) animation.getAnimatedValue(); + cellState.alpha = (1 - t) * startAlpha + t * endAlpha; + cellState.translationY = (1 - t) * startTranslationY + t * endTranslationY; + cellState.radius = mDotSize/2 * ((1 - t) * startScale + t * endScale); + invalidate(); + } + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (finishRunnable != null) { + finishRunnable.run(); + } + } + }); + animator.start(); + } + + private void startCellStateAnimationHw(final CellState cellState, + float startAlpha, float endAlpha, + float startTranslationY, float endTranslationY, + float startScale, float endScale, + long delay, long duration, Interpolator interpolator, final Runnable finishRunnable) { + cellState.alpha = endAlpha; + cellState.translationY = endTranslationY; + cellState.radius = mDotSize/2 * endScale; + cellState.hwAnimating = true; + cellState.hwCenterY = CanvasProperty.createFloat( + getCenterYForRow(cellState.row) + startTranslationY); + cellState.hwCenterX = CanvasProperty.createFloat(getCenterXForColumn(cellState.col)); + cellState.hwRadius = CanvasProperty.createFloat(mDotSize/2 * startScale); + mPaint.setColor(getCurrentColor(false)); + mPaint.setAlpha((int) (startAlpha * 255)); + cellState.hwPaint = CanvasProperty.createPaint(new Paint(mPaint)); + + startRtFloatAnimation(cellState.hwCenterY, + getCenterYForRow(cellState.row) + endTranslationY, delay, duration, interpolator); + startRtFloatAnimation(cellState.hwRadius, mDotSize/2 * endScale, delay, duration, + interpolator); + startRtAlphaAnimation(cellState, endAlpha, delay, duration, interpolator, + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + cellState.hwAnimating = false; + if (finishRunnable != null) { + finishRunnable.run(); + } + } + }); + + invalidate(); + } + + private void startRtAlphaAnimation(CellState cellState, float endAlpha, + long delay, long duration, Interpolator interpolator, + Animator.AnimatorListener listener) { + RenderNodeAnimator animator = new RenderNodeAnimator(cellState.hwPaint, + RenderNodeAnimator.PAINT_ALPHA, (int) (endAlpha * 255)); + animator.setDuration(duration); + animator.setStartDelay(delay); + animator.setInterpolator(interpolator); + animator.setTarget(this); + animator.addListener(listener); + animator.start(); + } + + private void startRtFloatAnimation(CanvasProperty<Float> property, float endValue, + long delay, long duration, Interpolator interpolator) { + RenderNodeAnimator animator = new RenderNodeAnimator(property, endValue); + animator.setDuration(duration); + animator.setStartDelay(delay); + animator.setInterpolator(interpolator); + animator.setTarget(this); + animator.start(); + } + private void notifyCellAdded() { // sendAccessEvent(R.string.lockscreen_access_pattern_cell_added); if (mOnPatternListener != null) { @@ -603,14 +719,15 @@ public class LockPatternView extends View { private void startCellActivatedAnimation(Cell cell) { final CellState cellState = mCellStates[cell.row][cell.column]; - startSizeAnimation(mDotSize, mDotSizeActivated, 96, mLinearOutSlowInInterpolator, + startRadiusAnimation(mDotSize/2, mDotSizeActivated/2, 96, mLinearOutSlowInInterpolator, cellState, new Runnable() { - @Override - public void run() { - startSizeAnimation(mDotSizeActivated, mDotSize, 192, mFastOutSlowInInterpolator, - cellState, null); - } - }); + @Override + public void run() { + startRadiusAnimation(mDotSizeActivated/2, mDotSize/2, 192, + mFastOutSlowInInterpolator, + cellState, null); + } + }); startLineEndAnimation(cellState, mInProgressX, mInProgressY, getCenterXForColumn(cell.column), getCenterYForRow(cell.row)); } @@ -639,13 +756,13 @@ public class LockPatternView extends View { state.lineAnimator = valueAnimator; } - private void startSizeAnimation(float start, float end, long duration, Interpolator interpolator, - final CellState state, final Runnable endRunnable) { + private void startRadiusAnimation(float start, float end, long duration, + Interpolator interpolator, final CellState state, final Runnable endRunnable) { ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - state.size = (float) animation.getAnimatedValue(); + state.radius = (float) animation.getAnimatedValue(); invalidate(); } }); @@ -969,10 +1086,16 @@ public class LockPatternView extends View { for (int j = 0; j < 3; j++) { CellState cellState = mCellStates[i][j]; float centerX = getCenterXForColumn(j); - float size = cellState.size * cellState.scale; - float translationY = cellState.translateY; - drawCircle(canvas, (int) centerX, (int) centerY + translationY, - size, drawLookup[i][j], cellState.alpha); + float translationY = cellState.translationY; + if (isHardwareAccelerated() && cellState.hwAnimating) { + DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas; + displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY, + cellState.hwRadius, cellState.hwPaint); + } else { + drawCircle(canvas, (int) centerX, (int) centerY + translationY, + cellState.radius, drawLookup[i][j], cellState.alpha); + + } } } @@ -1055,11 +1178,11 @@ public class LockPatternView extends View { /** * @param partOfPattern Whether this circle is part of the pattern. */ - private void drawCircle(Canvas canvas, float centerX, float centerY, float size, + private void drawCircle(Canvas canvas, float centerX, float centerY, float radius, boolean partOfPattern, float alpha) { mPaint.setColor(getCurrentColor(partOfPattern)); mPaint.setAlpha((int) (alpha * 255)); - canvas.drawCircle(centerX, centerY, size/2, mPaint); + canvas.drawCircle(centerX, centerY, radius, mPaint); } @Override @@ -1290,7 +1413,6 @@ public class LockPatternView extends View { float centerY = getCenterYForRow(row); float cellheight = mSquareHeight * mHitFactor * 0.5f; float cellwidth = mSquareWidth * mHitFactor * 0.5f; - float translationY = cell.translateY; bounds.left = (int) (centerX - cellwidth); bounds.right = (int) (centerX + cellwidth); bounds.top = (int) (centerY - cellheight); |
