diff options
Diffstat (limited to 'core/java/android')
38 files changed, 700 insertions, 300 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index f506d59..5dcbe37 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -96,7 +96,7 @@ import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.renderscript.RenderScriptCacheDir; -import android.security.AndroidKeyStoreProvider; +import android.security.keystore.AndroidKeyStoreProvider; import com.android.internal.app.IVoiceInteractor; import com.android.internal.content.ReferrerIntent; diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index 470804d..87e2f9a 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -24,6 +24,7 @@ import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.security.KeyChain; @@ -249,13 +250,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { public static final String EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID = "android.app.extra.CHOOSE_PRIVATE_KEY_SENDER_UID"; /** @hide */ - public static final String EXTRA_CHOOSE_PRIVATE_KEY_HOST = "android.app.extra.CHOOSE_PRIVATE_KEY_HOST"; - - /** @hide */ - public static final String EXTRA_CHOOSE_PRIVATE_KEY_PORT = "android.app.extra.CHOOSE_PRIVATE_KEY_PORT"; - - /** @hide */ - public static final String EXTRA_CHOOSE_PRIVATE_KEY_URL = "android.app.extra.CHOOSE_PRIVATE_KEY_URL"; + public static final String EXTRA_CHOOSE_PRIVATE_KEY_URI = "android.app.extra.CHOOSE_PRIVATE_KEY_URI"; /** @hide */ public static final String EXTRA_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.extra.CHOOSE_PRIVATE_KEY_ALIAS"; @@ -487,15 +482,13 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param context The running context as per {@link #onReceive}. * @param intent The received intent as per {@link #onReceive}. * @param uid The uid asking for the private key and certificate pair. - * @param host The authentication host, may be null. - * @param port The authentication port, or -1. - * @param url The URL to authenticate, may be null. + * @param uri The URI to authenticate, may be null. * @param alias The alias preselected by the client, or null. * @return The private key alias to return and grant access to. * @see KeyChain#choosePrivateKeyAlias */ - public String onChoosePrivateKeyAlias(Context context, Intent intent, int uid, String host, - int port, String url, String alias) { + public String onChoosePrivateKeyAlias(Context context, Intent intent, int uid, Uri uri, + String alias) { return null; } @@ -546,12 +539,9 @@ public class DeviceAdminReceiver extends BroadcastReceiver { onProfileProvisioningComplete(context, intent); } else if (ACTION_CHOOSE_PRIVATE_KEY_ALIAS.equals(action)) { int uid = intent.getIntExtra(EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID, -1); - String host = intent.getStringExtra(EXTRA_CHOOSE_PRIVATE_KEY_HOST); - int port = intent.getIntExtra(EXTRA_CHOOSE_PRIVATE_KEY_PORT, -1); - String url = intent.getStringExtra(EXTRA_CHOOSE_PRIVATE_KEY_URL); + Uri uri = intent.getParcelableExtra(EXTRA_CHOOSE_PRIVATE_KEY_URI); String alias = intent.getStringExtra(EXTRA_CHOOSE_PRIVATE_KEY_ALIAS); - String chosenAlias = onChoosePrivateKeyAlias(context, intent, uid, host, port, url, - alias); + String chosenAlias = onChoosePrivateKeyAlias(context, intent, uid, uri, alias); setResultData(chosenAlias); } else if (ACTION_LOCK_TASK_ENTERING.equals(action)) { String pkg = intent.getStringExtra(EXTRA_LOCK_TASK_PACKAGE); diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 71d044e..24ef604 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -23,6 +23,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; import android.net.ProxyInfo; +import android.net.Uri; import android.os.Bundle; import android.os.PersistableBundle; import android.os.RemoteCallback; @@ -131,7 +132,7 @@ interface IDevicePolicyManager { void enforceCanManageCaCerts(in ComponentName admin); boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer, String alias); - void choosePrivateKeyAlias(int uid, in String host, int port, in String url, in String alias, IBinder aliasCallback); + void choosePrivateKeyAlias(int uid, in Uri uri, in String alias, IBinder aliasCallback); void setCertInstallerPackage(in ComponentName who, String installerPackage); String getCertInstallerPackage(in ComponentName who); diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java index 9540eb1..4d2158f 100644 --- a/core/java/android/app/backup/BackupTransport.java +++ b/core/java/android/app/backup/BackupTransport.java @@ -162,8 +162,17 @@ public class BackupTransport { * this is called, {@link #finishBackup} will be called to ensure the request * is sent and received successfully. * + * <p>If the transport returns anything other than TRANSPORT_OK from this method, + * the OS will halt the current initialize operation and schedule a retry in the + * near future. Even if the transport is in a state such that attempting to + * "initialize" the backend storage is meaningless -- for example, if there is + * no current live dataset at all, or there is no authenticated account under which + * to store the data remotely -- the transport should return TRANSPORT_OK here + * and treat the initializeDevice() / finishBackup() pair as a graceful no-op. + * * @return One of {@link BackupTransport#TRANSPORT_OK} (OK so far) or - * {@link BackupTransport#TRANSPORT_ERROR} (on network error or other failure). + * {@link BackupTransport#TRANSPORT_ERROR} (to retry following network error + * or other failure). */ public int initializeDevice() { return BackupTransport.TRANSPORT_ERROR; diff --git a/core/java/android/app/usage/NetworkUsageStats.java b/core/java/android/app/usage/NetworkStats.java index 990d231..5193563 100644 --- a/core/java/android/app/usage/NetworkUsageStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -19,7 +19,6 @@ package android.app.usage; import android.content.Context; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; -import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; @@ -33,7 +32,7 @@ import dalvik.system.CloseGuard; * Class providing enumeration over buckets of network usage statistics. NetworkUsageStats objects * are returned as results to various queries in {@link NetworkStatsManager}. */ -public final class NetworkUsageStats implements AutoCloseable { +public final class NetworkStats implements AutoCloseable { private final static String TAG = "NetworkUsageStats"; private final CloseGuard mCloseGuard = CloseGuard.get(); @@ -70,7 +69,7 @@ public final class NetworkUsageStats implements AutoCloseable { /** * Results of a summary query. */ - private NetworkStats mSummary = null; + private android.net.NetworkStats mSummary = null; /** * Results of detail queries. @@ -85,11 +84,11 @@ public final class NetworkUsageStats implements AutoCloseable { /** * Recycling entry objects to prevent heap fragmentation. */ - private NetworkStats.Entry mRecycledSummaryEntry = null; + private android.net.NetworkStats.Entry mRecycledSummaryEntry = null; private NetworkStatsHistory.Entry mRecycledHistoryEntry = null; /** @hide */ - NetworkUsageStats(Context context, NetworkTemplate template, long startTimestamp, + NetworkStats(Context context, NetworkTemplate template, long startTimestamp, long endTimestamp) throws RemoteException, SecurityException { final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); @@ -136,14 +135,19 @@ public final class NetworkUsageStats implements AutoCloseable { public static final int STATE_FOREGROUND = 0x2; /** + * Special UID value for aggregate/unspecified. + */ + public static final int UID_ALL = android.net.NetworkStats.UID_ALL; + + /** * Special UID value for removed apps. */ - public static final int UID_REMOVED = -4; + public static final int UID_REMOVED = TrafficStats.UID_REMOVED; /** * Special UID value for data usage by tethering. */ - public static final int UID_TETHERING = -5; + public static final int UID_TETHERING = TrafficStats.UID_TETHERING; private int mUid; private int mState; @@ -156,9 +160,9 @@ public final class NetworkUsageStats implements AutoCloseable { private static int convertState(int networkStatsSet) { switch (networkStatsSet) { - case NetworkStats.SET_ALL : return STATE_ALL; - case NetworkStats.SET_DEFAULT : return STATE_DEFAULT; - case NetworkStats.SET_FOREGROUND : return STATE_FOREGROUND; + case android.net.NetworkStats.SET_ALL : return STATE_ALL; + case android.net.NetworkStats.SET_DEFAULT : return STATE_DEFAULT; + case android.net.NetworkStats.SET_FOREGROUND : return STATE_FOREGROUND; } return 0; } @@ -337,8 +341,8 @@ public final class NetworkUsageStats implements AutoCloseable { void startHistoryEnumeration(int uid) { mHistory = null; try { - mHistory = mSession.getHistoryForUid(mTemplate, uid, NetworkStats.SET_ALL, - NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL); + mHistory = mSession.getHistoryForUid(mTemplate, uid, android.net.NetworkStats.SET_ALL, + android.net.NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL); setSingleUid(uid); } catch (RemoteException e) { Log.w(TAG, e); @@ -364,8 +368,9 @@ public final class NetworkUsageStats implements AutoCloseable { stepUid(); mHistory = null; try { - mHistory = mSession.getHistoryForUid(mTemplate, getUid(), NetworkStats.SET_ALL, - NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL); + mHistory = mSession.getHistoryForUid(mTemplate, getUid(), + android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE, + NetworkStatsHistory.FIELD_ALL); } catch (RemoteException e) { Log.w(TAG, e); // Leaving mHistory null @@ -405,7 +410,7 @@ public final class NetworkUsageStats implements AutoCloseable { } Bucket bucket = new Bucket(); if (mRecycledSummaryEntry == null) { - mRecycledSummaryEntry = new NetworkStats.Entry(); + mRecycledSummaryEntry = new android.net.NetworkStats.Entry(); } mSummary.getTotal(mRecycledSummaryEntry); fillBucketFromSummaryEntry(bucket); diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index af7c053..2ae0181 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -16,18 +16,17 @@ package android.app.usage; -import android.app.usage.NetworkUsageStats.Bucket; +import android.app.usage.NetworkStats.Bucket; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkIdentity; import android.net.NetworkTemplate; import android.os.RemoteException; -import android.os.UserHandle; import android.util.Log; /** * Provides access to network usage history and statistics. Usage data is collected in - * discrete bins of time called 'Buckets'. See {@link NetworkUsageStats.Bucket} for details. + * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details. * <p /> * Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and * Long.MAX_VALUE can be used to simulate open ended intervals). All queries (except @@ -37,15 +36,20 @@ import android.util.Log; * <h3> * Summary queries * </h3> + * {@link #querySummaryForDevice} <p /> + * {@link #querySummaryForUser} <p /> + * {@link #querySummary} <p /> * These queries aggregate network usage across the whole interval. Therefore there will be only one * bucket for a particular key and state combination. In case of the user-wide and device-wide * summaries a single bucket containing the totalised network usage is returned. * <h3> * History queries * </h3> + * {@link #queryDetailsForUid} <p /> + * {@link #queryDetails} <p /> * These queries do not aggregate over time but do aggregate over state. Therefore there can be * multiple buckets for a particular key but all Bucket's state is going to be - * {@link NetworkUsageStats.Bucket#STATE_ALL}. + * {@link NetworkStats.Bucket#STATE_ALL}. * <p /> * <b>NOTE:</b> This API requires the permission * {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, which is a system-level permission and @@ -68,7 +72,10 @@ public class NetworkStatsManager { } /** * Query network usage statistics summaries. Result is summarised data usage for the whole - * device. Result is a single Bucket aggregated over time, state and uid. + * device. Result is a single Bucket aggregated over time, state and uid. This means the + * bucket's start and end timestamp are going to be the same as the 'startTime' and 'endTime' + * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid + * {@link NetworkStats.Bucket#UID_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -89,7 +96,7 @@ public class NetworkStatsManager { } Bucket bucket = null; - NetworkUsageStats stats = new NetworkUsageStats(mContext, template, startTime, endTime); + NetworkStats stats = new NetworkStats(mContext, template, startTime, endTime); bucket = stats.getDeviceSummaryForNetwork(startTime, endTime); stats.close(); @@ -99,6 +106,9 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result is summarised data usage for all uids * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. + * This means the bucket's start and end timestamp are going to be the same as the 'startTime' + * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid + * {@link NetworkStats.Bucket#UID_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -118,8 +128,8 @@ public class NetworkStatsManager { return null; } - NetworkUsageStats stats; - stats = new NetworkUsageStats(mContext, template, startTime, endTime); + NetworkStats stats; + stats = new NetworkStats(mContext, template, startTime, endTime); stats.startSummaryEnumeration(startTime, endTime); stats.close(); @@ -129,7 +139,9 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. Not aggregated over state or uid. + * end timestamps. Not aggregated over state or uid. This means buckets' start and end + * timestamps are going to be the same as the 'startTime' and 'endTime' parameters, state and + * uid are going to vary. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -142,15 +154,15 @@ public class NetworkStatsManager { * @return Statistics object or null if permissions are insufficient or error happened during * statistics collection. */ - public NetworkUsageStats querySummary(int networkType, String subscriberId, long startTime, + public NetworkStats querySummary(int networkType, String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template = createTemplate(networkType, subscriberId); if (template == null) { return null; } - NetworkUsageStats result; - result = new NetworkUsageStats(mContext, template, startTime, endTime); + NetworkStats result; + result = new NetworkStats(mContext, template, startTime, endTime); result.startSummaryEnumeration(startTime, endTime); return result; @@ -158,7 +170,9 @@ public class NetworkStatsManager { /** * Query network usage statistics details. Only usable for uids belonging to calling user. - * Result is aggregated over state but not aggregated over time. + * Result is aggregated over state but not aggregated over time. This means buckets' start and + * end timestamps are going to be between 'startTime' and 'endTime' parameters, state is going + * to be {@link NetworkStats.Bucket#STATE_ALL} and uid the same as the 'uid' parameter. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -172,15 +186,15 @@ public class NetworkStatsManager { * @return Statistics object or null if permissions are insufficient or error happened during * statistics collection. */ - public NetworkUsageStats queryDetailsForUid(int networkType, String subscriberId, + public NetworkStats queryDetailsForUid(int networkType, String subscriberId, long startTime, long endTime, int uid) throws SecurityException, RemoteException { NetworkTemplate template = createTemplate(networkType, subscriberId); if (template == null) { return null; } - NetworkUsageStats result; - result = new NetworkUsageStats(mContext, template, startTime, endTime); + NetworkStats result; + result = new NetworkStats(mContext, template, startTime, endTime); result.startHistoryEnumeration(uid); return result; @@ -188,7 +202,9 @@ public class NetworkStatsManager { /** * Query network usage statistics details. Result filtered to include only uids belonging to - * calling user. Result is aggregated over state but not aggregated over time or uid. + * calling user. Result is aggregated over state but not aggregated over time or uid. This means + * buckets' start and end timestamps are going to be between 'startTime' and 'endTime' + * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid will vary. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -201,14 +217,14 @@ public class NetworkStatsManager { * @return Statistics object or null if permissions are insufficient or error happened during * statistics collection. */ - public NetworkUsageStats queryDetails(int networkType, String subscriberId, long startTime, + public NetworkStats queryDetails(int networkType, String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template = createTemplate(networkType, subscriberId); if (template == null) { return null; } - NetworkUsageStats result; - result = new NetworkUsageStats(mContext, template, startTime, endTime); + NetworkStats result; + result = new NetworkStats(mContext, template, startTime, endTime); result.startUserUidEnumeration(); return result; } diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index c74bbdd..34699d8 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -234,4 +234,15 @@ public final class UsageStatsManager { } return false; } + + /** + * @hide + */ + public void setAppInactive(String packageName, boolean inactive) { + try { + mService.setAppInactive(packageName, inactive, UserHandle.myUserId()); + } catch (RemoteException e) { + // fall through + } + } } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 202a8a7..2ca0306 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -653,6 +653,16 @@ public abstract class PackageManager { public static final int INSTALL_FAILED_VERSION_DOWNGRADE = -25; /** + * Installation return code: this is passed to the {@link IPackageInstallObserver} by + * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if + * the old package has target SDK high enough to support runtime permission and + * the new package has target SDK low enough to not support runtime permissions. + * @hide + */ + @SystemApi + public static final int INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE = -26; + + /** * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser was given a path that is not a file, or does not end with the expected @@ -4512,6 +4522,7 @@ public abstract class PackageManager { case INSTALL_FAILED_PACKAGE_CHANGED: return PackageInstaller.STATUS_FAILURE_INVALID; case INSTALL_FAILED_UID_CHANGED: return PackageInstaller.STATUS_FAILURE_INVALID; case INSTALL_FAILED_VERSION_DOWNGRADE: return PackageInstaller.STATUS_FAILURE_INVALID; + case INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE: return PackageInstaller.STATUS_FAILURE_INVALID; case INSTALL_PARSE_FAILED_NOT_APK: return PackageInstaller.STATUS_FAILURE_INVALID; case INSTALL_PARSE_FAILED_BAD_MANIFEST: return PackageInstaller.STATUS_FAILURE_INVALID; case INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: return PackageInstaller.STATUS_FAILURE_INVALID; diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java index c2d2f65..0bd2a3b 100644 --- a/core/java/android/content/pm/RegisteredServicesCache.java +++ b/core/java/android/content/pm/RegisteredServicesCache.java @@ -52,6 +52,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -573,7 +574,7 @@ public abstract class RegisteredServicesCache<V> { private void readPersistentServicesLocked(InputStream is) throws XmlPullParserException, IOException { XmlPullParser parser = Xml.newPullParser(); - parser.setInput(is, null); + parser.setInput(is, StandardCharsets.UTF_8.name()); int eventType = parser.getEventType(); while (eventType != XmlPullParser.START_TAG && eventType != XmlPullParser.END_DOCUMENT) { @@ -663,7 +664,7 @@ public abstract class RegisteredServicesCache<V> { try { fos = atomicFile.startWrite(); XmlSerializer out = new FastXmlSerializer(); - out.setOutput(fos, "utf-8"); + out.setOutput(fos, StandardCharsets.UTF_8.name()); out.startDocument(null, true); out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); out.startTag(null, "services"); diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java index f70e075..c6f622c 100644 --- a/core/java/android/hardware/camera2/CameraCaptureSession.java +++ b/core/java/android/hardware/camera2/CameraCaptureSession.java @@ -29,11 +29,11 @@ import java.util.List; * <p>A CameraCaptureSession is created by providing a set of target output surfaces to * {@link CameraDevice#createCaptureSession createCaptureSession}, or by providing an * {@link android.hardware.camera2.params.InputConfiguration} and a set of target output surfaces to - * {@link CameraDevice#createReprocessibleCaptureSession createReprocessibleCaptureSession} for a - * reprocessible capture session. Once created, the session is active until a new session is + * {@link CameraDevice#createReprocessableCaptureSession createReprocessableCaptureSession} for a + * reprocessable capture session. Once created, the session is active until a new session is * created by the camera device, or the camera device is closed.</p> * - * <p>All capture sessions can be used for capturing images from the camera but only reprocessible + * <p>All capture sessions can be used for capturing images from the camera but only reprocessable * capture sessions can reprocess images captured from the camera in the same session previously. * </p> * @@ -41,7 +41,7 @@ import java.util.List; * it requires configuring the camera device's internal pipelines and allocating memory buffers for * sending images to the desired targets. Therefore the setup is done asynchronously, and * {@link CameraDevice#createCaptureSession createCaptureSession} and - * {@link CameraDevice#createReprocessibleCaptureSession createReprocessibleCaptureSession} will + * {@link CameraDevice#createReprocessableCaptureSession createReprocessableCaptureSession} will * send the ready-to-use CameraCaptureSession to the provided listener's * {@link CameraCaptureSession.StateCallback#onConfigured onConfigured} callback. If configuration * cannot be completed, then the @@ -156,7 +156,7 @@ public abstract class CameraCaptureSession implements AutoCloseable { * * <p>All capture sessions can be used for capturing images from the camera but only capture * sessions created by - * {@link CameraDevice#createReprocessibleCaptureSession createReprocessibleCaptureSession} + * {@link CameraDevice#createReprocessableCaptureSession createReprocessableCaptureSession} * can submit reprocess capture requests. Submitting a reprocess request to a regular capture * session will result in an {@link IllegalArgumentException}.</p> * @@ -179,9 +179,9 @@ public abstract class CameraCaptureSession implements AutoCloseable { * @throws IllegalArgumentException if the request targets no Surfaces or Surfaces that are not * configured as outputs for this session; or the request * targets a set of Surfaces that cannot be submitted - * simultaneously in a reprocessible capture session; or a + * simultaneously in a reprocessable capture session; or a * reprocess capture request is submitted in a - * non-reprocessible capture session; or the reprocess capture + * non-reprocessable capture session; or the reprocess capture * request was created with a {@link TotalCaptureResult} from * a different session; or the capture targets a Surface in * the middle of being {@link #prepare prepared}; or the @@ -192,7 +192,7 @@ public abstract class CameraCaptureSession implements AutoCloseable { * @see #setRepeatingRequest * @see #setRepeatingBurst * @see #abortCaptures - * @see CameraDevice#createReprocessibleCaptureSession + * @see CameraDevice#createReprocessableCaptureSession */ public abstract int capture(CaptureRequest request, CaptureCallback listener, Handler handler) throws CameraAccessException; @@ -214,7 +214,7 @@ public abstract class CameraCaptureSession implements AutoCloseable { * * <p>All capture sessions can be used for capturing images from the camera but only capture * sessions created by - * {@link CameraDevice#createReprocessibleCaptureSession createReprocessibleCaptureSession} + * {@link CameraDevice#createReprocessableCaptureSession createReprocessableCaptureSession} * can submit reprocess capture requests. Submitting a reprocess request to a regular * capture session will result in an {@link IllegalArgumentException}.</p> * @@ -238,9 +238,9 @@ public abstract class CameraCaptureSession implements AutoCloseable { * @throws IllegalArgumentException If the requests target no Surfaces, or the requests target * Surfaces not currently configured as outputs; or one of the * requests targets a set of Surfaces that cannot be submitted - * simultaneously in a reprocessible capture session; or a + * simultaneously in a reprocessable capture session; or a * reprocess capture request is submitted in a - * non-reprocessible capture session; or one of the reprocess + * non-reprocessable capture session; or one of the reprocess * capture requests was created with a * {@link TotalCaptureResult} from a different session; or one * of the captures targets a Surface in the middle of being @@ -425,7 +425,7 @@ public abstract class CameraCaptureSession implements AutoCloseable { * * <p>This method is the fastest way to switch the camera device to a new session with * {@link CameraDevice#createCaptureSession} or - * {@link CameraDevice#createReprocessibleCaptureSession}, at the cost of discarding in-progress + * {@link CameraDevice#createReprocessableCaptureSession}, at the cost of discarding in-progress * work. It must be called before the new session is created. Once all pending requests are * either completed or thrown away, the {@link StateCallback#onReady} callback will be called, * if the session has not been closed. Otherwise, the {@link StateCallback#onClosed} @@ -448,7 +448,7 @@ public abstract class CameraCaptureSession implements AutoCloseable { * @see #setRepeatingRequest * @see #setRepeatingBurst * @see CameraDevice#createCaptureSession - * @see CameraDevice#createReprocessibleCaptureSession + * @see CameraDevice#createReprocessableCaptureSession */ public abstract void abortCaptures() throws CameraAccessException; @@ -459,14 +459,14 @@ public abstract class CameraCaptureSession implements AutoCloseable { * @return {@code true} if the application can submit reprocess capture requests with this * camera capture session. {@code false} otherwise. * - * @see CameraDevice#createReprocessibleCaptureSession + * @see CameraDevice#createReprocessableCaptureSession */ - public abstract boolean isReprocessible(); + public abstract boolean isReprocessable(); /** - * Get the input Surface associated with a reprocessible capture session. + * Get the input Surface associated with a reprocessable capture session. * - * <p>Each reprocessible capture session has an input {@link Surface} where the reprocess + * <p>Each reprocessable capture session has an input {@link Surface} where the reprocess * capture requests get the input images from, rather than the camera device. The application * can create a {@link android.media.ImageWriter} with this input {@link Surface} and use it to * provide input images for reprocess capture requests.</p> @@ -474,7 +474,7 @@ public abstract class CameraCaptureSession implements AutoCloseable { * @return The {@link Surface} where reprocessing capture requests get the input images from. If * this is not a reprocess capture session, {@code null} will be returned. * - * @see CameraDevice#createReprocessibleCaptureSession + * @see CameraDevice#createReprocessableCaptureSession * @see android.media.ImageWriter * @see android.media.ImageReader */ diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 19e821c..d3b63f9 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -1239,7 +1239,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * only the input buffer will be used to produce these output stream buffers, and a * new sensor image will not be captured.</p> * <p>For example, for Zero Shutter Lag (ZSL) still capture use case, the input - * stream image format will be OPAQUE, the associated output stream image format + * stream image format will be PRIVATE, the associated output stream image format * should be JPEG.</p> * <p><b>Range of valid values:</b><br></p> * <p>0 or 1.</p> @@ -1326,7 +1326,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR MANUAL_SENSOR}</li> * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING MANUAL_POST_PROCESSING}</li> * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}</li> - * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING OPAQUE_REPROCESSING}</li> + * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING PRIVATE_REPROCESSING}</li> * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS READ_SENSOR_SETTINGS}</li> * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}</li> * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING YUV_REPROCESSING}</li> @@ -1339,7 +1339,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR * @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING * @see #REQUEST_AVAILABLE_CAPABILITIES_RAW - * @see #REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING + * @see #REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING * @see #REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS * @see #REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE * @see #REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING @@ -1536,12 +1536,12 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <tr> * <td align="left">{@link android.graphics.ImageFormat#PRIVATE }</td> * <td align="left">{@link android.graphics.ImageFormat#JPEG }</td> - * <td align="left">OPAQUE_REPROCESSING</td> + * <td align="left">PRIVATE_REPROCESSING</td> * </tr> * <tr> * <td align="left">{@link android.graphics.ImageFormat#PRIVATE }</td> * <td align="left">{@link android.graphics.ImageFormat#YUV_420_888 }</td> - * <td align="left">OPAQUE_REPROCESSING</td> + * <td align="left">PRIVATE_REPROCESSING</td> * </tr> * <tr> * <td align="left">{@link android.graphics.ImageFormat#YUV_420_888 }</td> @@ -1556,8 +1556,9 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * </tbody> * </table> * <p>PRIVATE refers to a device-internal format that is not directly application-visible. A - * PRIVATE input surface can be acquired by {@link android.media.ImageReader#newOpaqueInstance }.</p> - * <p>For a OPAQUE_REPROCESSING-capable camera device, using the PRIVATE format as either input + * PRIVATE input surface can be acquired by {@link android.media.ImageReader#newInstance } + * with {@link android.graphics.ImageFormat#PRIVATE } as the format.</p> + * <p>For a PRIVATE_REPROCESSING-capable camera device, using the PRIVATE format as either input * or output will never hurt maximum frame rate (i.e. {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration getOutputStallDuration(ImageFormat.PRIVATE, size)} is always 0),</p> * <p>Attempting to configure an input stream with output streams not * listed as available in this map is not valid.</p> @@ -2647,8 +2648,8 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * formats/sizes combination.</p> * <p>If this key reports 0, it means a reprocess request doesn't introduce any glitch to the * ongoing camera repeating request outputs, as if this reprocess request is never issued.</p> - * <p>This key is supported if the camera device supports OPAQUE or YUV reprocessing ( - * i.e. {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains OPAQUE_REPROCESSING or + * <p>This key is supported if the camera device supports PRIVATE or YUV reprocessing ( + * i.e. {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains PRIVATE_REPROCESSING or * YUV_REPROCESSING).</p> * <p><b>Units</b>: Number of frames.</p> * <p><b>Range of valid values:</b><br> diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index 4af7daf..dad4fb6 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -100,7 +100,7 @@ public abstract class CameraDevice implements AutoCloseable { * means maximizing image quality without compromising preview frame rate. * AE/AWB/AF should be on auto mode. * This template is guaranteed to be supported on camera devices that support the - * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING OPAQUE_REPROCESSING} + * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING PRIVATE_REPROCESSING} * capability or the * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING YUV_REPROCESSING} * capability. @@ -409,15 +409,15 @@ public abstract class CameraDevice implements AutoCloseable { CameraCaptureSession.StateCallback callback, Handler handler) throws CameraAccessException; /** - * Create a new reprocessible camera capture session by providing the desired reprocessing + * Create a new reprocessable camera capture session by providing the desired reprocessing * input Surface configuration and the target output set of Surfaces to the camera device. * * <p>If a camera device supports YUV reprocessing - * ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING}) or OPAQUE + * ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING}) or PRIVATE * reprocessing - * ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING}), besides + * ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING}), besides * the capture session created via {@link #createCaptureSession createCaptureSession}, the - * application can also create a reprocessible capture session to submit reprocess capture + * application can also create a reprocessable capture session to submit reprocess capture * requests in addition to regular capture requests. A reprocess capture request takes the next * available buffer from the session's input Surface, and sends it through the camera device's * processing pipeline again, to produce buffers for the request's target output Surfaces. No @@ -426,7 +426,7 @@ public abstract class CameraDevice implements AutoCloseable { * directly (e.g. for Zero-Shutter-Lag use case) or indirectly (e.g. combining multiple output * images).</p> * - * <p>The active reprocessible capture session determines an input {@link Surface} and the set + * <p>The active reprocessable capture session determines an input {@link Surface} and the set * of potential output Surfaces for the camera devices for each capture request. The application * can use {@link #createCaptureRequest createCaptureRequest} to create regular capture requests * to capture new images from the camera device, and use {@link #createReprocessCaptureRequest @@ -448,30 +448,30 @@ public abstract class CameraDevice implements AutoCloseable { * they cannot be used as targets for a reprocessing request.</p> * * <p>Since the application cannot access {@link android.graphics.ImageFormat#PRIVATE} images - * directly, an output Surface created by {@link android.media.ImageReader#newOpaqueInstance} - * will be considered as intended to be used for reprocessing input and thus the - * {@link android.media.ImageReader} size must match one of the supported input sizes for - * {@link android.graphics.ImageFormat#PRIVATE} format. Otherwise, creating a reprocessible - * capture session will fail.</p> + * directly, an output Surface created by {@link android.media.ImageReader#newInstance} with + * {@link android.graphics.ImageFormat#PRIVATE} as the format will be considered as intended to + * be used for reprocessing input and thus the {@link android.media.ImageReader} size must + * match one of the supported input sizes for {@link android.graphics.ImageFormat#PRIVATE} + * format. Otherwise, creating a reprocessable capture session will fail.</p> * * <p>The guaranteed stream configurations listed in * {@link #createCaptureSession createCaptureSession} are also guaranteed to work for - * {@link #createReprocessibleCaptureSession createReprocessibleCaptureSession}. In addition, - * the configurations in the tables below are also guaranteed for creating a reprocessible - * capture session if the camera device supports YUV reprocessing or OPAQUE reprocessing. - * However, not all output targets used to create a reprocessible session may be used in a + * {@link #createReprocessableCaptureSession createReprocessableCaptureSession}. In addition, + * the configurations in the tables below are also guaranteed for creating a reprocessable + * capture session if the camera device supports YUV reprocessing or PRIVATE reprocessing. + * However, not all output targets used to create a reprocessable session may be used in a * {@link CaptureRequest} simultaneously. The guaranteed output targets that can be included * in a {@link CaptureRequest} simultaneously are listed in the tables under * {@link #createCaptureSession createCaptureSession}. For example, with a FULL-capability * ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} {@code == } - * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) device that supports OPAQUE - * reprocessing, an application can create a reprocessible capture session with 1 input, + * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) device that supports PRIVATE + * reprocessing, an application can create a reprocessable capture session with 1 input, * ({@code PRIV}, {@code MAXIMUM}), and 3 outputs, ({@code PRIV}, {@code MAXIMUM}), * ({@code PRIV}, {@code PREVIEW}), and ({@code YUV}, {@code MAXIMUM}). However, it's not * guaranteed that an application can submit a regular or reprocess capture with ({@code PRIV}, * {@code MAXIMUM}) and ({@code YUV}, {@code MAXIMUM}) outputs based on the table listed under * {@link #createCaptureSession createCaptureSession}. In other words, use the tables below to - * determine the guaranteed stream configurations for creating a reprocessible capture session, + * determine the guaranteed stream configurations for creating a reprocessable capture session, * and use the tables under {@link #createCaptureSession createCaptureSession} to determine the * guaranteed output targets that can be submitted in a regular or reprocess * {@link CaptureRequest} simultaneously.</p> @@ -482,12 +482,12 @@ public abstract class CameraDevice implements AutoCloseable { * * <p>Limited-capability ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}) devices - * support at least the following stream combinations for creating a reprocessible capture + * support at least the following stream combinations for creating a reprocessable capture * session in addition to those listed in {@link #createCaptureSession createCaptureSession} for * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices: * * <table> - * <tr><th colspan="11">LIMITED-level additional guaranteed configurations for creating a reprocessible capture session<br>({@code PRIV} input is guaranteed only if OPAQUE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr> + * <tr><th colspan="11">LIMITED-level additional guaranteed configurations for creating a reprocessable capture session<br>({@code PRIV} input is guaranteed only if PRIVATE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr> * <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr> * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr> * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td></td><td id="rb"></td> <td></td><td id="rb"></td> <td>No-viewfinder still image reprocessing.</td> </tr> @@ -499,12 +499,12 @@ public abstract class CameraDevice implements AutoCloseable { * * <p>FULL-capability ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices - * support at least the following stream combinations for creating a reprocessible capture + * support at least the following stream combinations for creating a reprocessable capture * session in addition to those for * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices: * * <table> - * <tr><th colspan="11">FULL-capability additional guaranteed configurations for creating a reprocessible capture session<br>({@code PRIV} input is guaranteed only if OPAQUE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr> + * <tr><th colspan="11">FULL-capability additional guaranteed configurations for creating a reprocessable capture session<br>({@code PRIV} input is guaranteed only if PRIVATE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr> * <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr> * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr> * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td></td><td id="rb"></td> <td></td><td id="rb"></td> <td>Maximum-resolution multi-frame image fusion in-app processing with regular preview.</td> </tr> @@ -520,12 +520,12 @@ public abstract class CameraDevice implements AutoCloseable { * * <p>RAW-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}) devices additionally support - * at least the following stream combinations for creating a reprocessible capture session + * at least the following stream combinations for creating a reprocessable capture session * on both {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} and * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices * * <table> - * <tr><th colspan="11">RAW-capability additional guaranteed configurations for creating a reprocessible capture session<br>({@code PRIV} input is guaranteed only if OPAQUE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr> + * <tr><th colspan="11">RAW-capability additional guaranteed configurations for creating a reprocessable capture session<br>({@code PRIV} input is guaranteed only if PRIVATE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr> * <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr> * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr> * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td></td><td id="rb"></td> <td>Mutually exclusive ZSL in-app processing and DNG capture.</td> </tr> @@ -560,7 +560,7 @@ public abstract class CameraDevice implements AutoCloseable { * @see android.media.ImageWriter * @see android.media.ImageReader */ - public abstract void createReprocessibleCaptureSession(InputConfiguration inputConfig, + public abstract void createReprocessableCaptureSession(InputConfiguration inputConfig, List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler) throws CameraAccessException; @@ -602,8 +602,7 @@ public abstract class CameraDevice implements AutoCloseable { * {@link CameraCaptureSession}'s input {@link Surface} to all output {@link Surface Surfaces} * included in the reprocess capture request. The reprocess input images must be generated from * one or multiple output images captured from the same camera device. The application can - * provide input images to camera device via - * {{@link android.media.ImageWriter#queueInputImage ImageWriter#queueInputImage}}. + * provide input images to camera device via {@link android.media.ImageWriter#queueInputImage}. * The application must use the capture result of one of those output images to create a * reprocess capture request so that the camera device can use the information to achieve * optimal reprocess image quality. @@ -618,7 +617,7 @@ public abstract class CameraDevice implements AutoCloseable { * * @see CaptureRequest.Builder * @see TotalCaptureResult - * @see CameraDevice#createReprocessibleCaptureSession + * @see CameraDevice#createReprocessableCaptureSession * @see android.media.ImageWriter */ public abstract CaptureRequest.Builder createReprocessCaptureRequest( diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 9327f00..d99cce7 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -556,7 +556,7 @@ public final class CameraManager { * {@link CameraManager#registerTorchCallback} to be notified of such status changes. * </p> * - * @see registerTorchCallback + * @see #registerTorchCallback */ public static abstract class TorchCallback { /** diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index ca9439b..6baa660 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -388,8 +388,8 @@ public abstract class CameraMetadata<TKey> { * <li>{@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}</li> * <li>{@link CaptureRequest#TONEMAP_MODE android.tonemap.mode}</li> * <li>{@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</li> - * <li>android.tonemap.gamma</li> - * <li>android.tonemap.presetCurve</li> + * <li>{@link CaptureRequest#TONEMAP_GAMMA android.tonemap.gamma}</li> + * <li>{@link CaptureRequest#TONEMAP_PRESET_CURVE android.tonemap.presetCurve}</li> * </ul> * </li> * <li> @@ -429,8 +429,10 @@ public abstract class CameraMetadata<TKey> { * @see CaptureRequest#SHADING_MODE * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE * @see CaptureRequest#TONEMAP_CURVE + * @see CaptureRequest#TONEMAP_GAMMA * @see CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS * @see CaptureRequest#TONEMAP_MODE + * @see CaptureRequest#TONEMAP_PRESET_CURVE * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES */ public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2; @@ -472,7 +474,7 @@ public abstract class CameraMetadata<TKey> { * <li>{@link android.graphics.ImageFormat#PRIVATE } will be reprocessable into both * {@link android.graphics.ImageFormat#YUV_420_888 } and * {@link android.graphics.ImageFormat#JPEG } formats.</li> - * <li>The maximum available resolution for OPAQUE streams + * <li>The maximum available resolution for PRIVATE streams * (both input/output) will match the maximum available * resolution of JPEG streams.</li> * <li>Static metadata {@link CameraCharacteristics#REPROCESS_MAX_CAPTURE_STALL android.reprocess.maxCaptureStall}.</li> @@ -492,7 +494,7 @@ public abstract class CameraMetadata<TKey> { * @see CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES */ - public static final int REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING = 4; + public static final int REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING = 4; /** * <p>The camera device supports accurately reporting the sensor settings for many of @@ -565,7 +567,7 @@ public abstract class CameraMetadata<TKey> { /** * <p>The camera device supports the YUV_420_888 reprocessing use case, similar as - * OPAQUE_REPROCESSING, This capability requires the camera device to support the + * PRIVATE_REPROCESSING, This capability requires the camera device to support the * following:</p> * <ul> * <li>One input stream is supported, that is, <code>{@link CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS android.request.maxNumInputStreams} == 1</code>.</li> @@ -2185,22 +2187,26 @@ public abstract class CameraMetadata<TKey> { public static final int TONEMAP_MODE_HIGH_QUALITY = 2; /** - * <p>Use the gamma value specified in android.tonemap.gamma to peform + * <p>Use the gamma value specified in {@link CaptureRequest#TONEMAP_GAMMA android.tonemap.gamma} to peform * tonemapping.</p> * <p>All color enhancement and tonemapping must be disabled, except - * for applying the tonemapping curve specified by android.tonemap.gamma.</p> + * for applying the tonemapping curve specified by {@link CaptureRequest#TONEMAP_GAMMA android.tonemap.gamma}.</p> * <p>Must not slow down frame rate relative to raw sensor output.</p> + * + * @see CaptureRequest#TONEMAP_GAMMA * @see CaptureRequest#TONEMAP_MODE */ public static final int TONEMAP_MODE_GAMMA_VALUE = 3; /** * <p>Use the preset tonemapping curve specified in - * android.tonemap.presetCurve to peform tonemapping.</p> + * {@link CaptureRequest#TONEMAP_PRESET_CURVE android.tonemap.presetCurve} to peform tonemapping.</p> * <p>All color enhancement and tonemapping must be disabled, except * for applying the tonemapping curve specified by - * android.tonemap.presetCurve.</p> + * {@link CaptureRequest#TONEMAP_PRESET_CURVE android.tonemap.presetCurve}.</p> * <p>Must not slow down frame rate relative to raw sensor output.</p> + * + * @see CaptureRequest#TONEMAP_PRESET_CURVE * @see CaptureRequest#TONEMAP_MODE */ public static final int TONEMAP_MODE_PRESET_CURVE = 4; diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index ab6ce91..3ec11b7 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -158,9 +158,9 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> private final HashSet<Surface> mSurfaceSet; private final CameraMetadataNative mSettings; private boolean mIsReprocess; - // Each reprocess request must be tied to a reprocessible session ID. + // Each reprocess request must be tied to a reprocessable session ID. // Valid only for reprocess requests (mIsReprocess == true). - private int mReprocessibleSessionId; + private int mReprocessableSessionId; private Object mUserTag; @@ -173,7 +173,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> mSettings = new CameraMetadataNative(); mSurfaceSet = new HashSet<Surface>(); mIsReprocess = false; - mReprocessibleSessionId = CameraCaptureSession.SESSION_ID_NONE; + mReprocessableSessionId = CameraCaptureSession.SESSION_ID_NONE; } /** @@ -186,7 +186,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> mSettings = new CameraMetadataNative(source.mSettings); mSurfaceSet = (HashSet<Surface>) source.mSurfaceSet.clone(); mIsReprocess = source.mIsReprocess; - mReprocessibleSessionId = source.mReprocessibleSessionId; + mReprocessableSessionId = source.mReprocessableSessionId; mUserTag = source.mUserTag; } @@ -199,30 +199,30 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * @param isReprocess Indicates whether to create a reprocess capture request. {@code true} * to create a reprocess capture request. {@code false} to create a regular * capture request. - * @param reprocessibleSessionId The ID of the camera capture session this capture is created + * @param reprocessableSessionId The ID of the camera capture session this capture is created * for. This is used to validate if the application submits a * reprocess capture request to the same session where * the {@link TotalCaptureResult}, used to create the reprocess * capture, came from. * * @throws IllegalArgumentException If creating a reprocess capture request with an invalid - * reprocessibleSessionId. + * reprocessableSessionId. * * @see CameraDevice#createReprocessCaptureRequest */ private CaptureRequest(CameraMetadataNative settings, boolean isReprocess, - int reprocessibleSessionId) { + int reprocessableSessionId) { mSettings = CameraMetadataNative.move(settings); mSurfaceSet = new HashSet<Surface>(); mIsReprocess = isReprocess; if (isReprocess) { - if (reprocessibleSessionId == CameraCaptureSession.SESSION_ID_NONE) { + if (reprocessableSessionId == CameraCaptureSession.SESSION_ID_NONE) { throw new IllegalArgumentException("Create a reprocess capture request with an " + - "invalid session ID: " + reprocessibleSessionId); + "invalid session ID: " + reprocessableSessionId); } - mReprocessibleSessionId = reprocessibleSessionId; + mReprocessableSessionId = reprocessableSessionId; } else { - mReprocessibleSessionId = CameraCaptureSession.SESSION_ID_NONE; + mReprocessableSessionId = CameraCaptureSession.SESSION_ID_NONE; } } @@ -307,20 +307,20 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> } /** - * Get the reprocessible session ID this reprocess capture request is associated with. + * Get the reprocessable session ID this reprocess capture request is associated with. * - * @return the reprocessible session ID this reprocess capture request is associated with + * @return the reprocessable session ID this reprocess capture request is associated with * * @throws IllegalStateException if this capture request is not a reprocess capture request. * @hide */ - public int getReprocessibleSessionId() { + public int getReprocessableSessionId() { if (mIsReprocess == false || - mReprocessibleSessionId == CameraCaptureSession.SESSION_ID_NONE) { - throw new IllegalStateException("Getting the reprocessible session ID for a "+ + mReprocessableSessionId == CameraCaptureSession.SESSION_ID_NONE) { + throw new IllegalStateException("Getting the reprocessable session ID for a "+ "non-reprocess capture request is illegal."); } - return mReprocessibleSessionId; + return mReprocessableSessionId; } /** @@ -346,7 +346,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> && mSurfaceSet.equals(other.mSurfaceSet) && mSettings.equals(other.mSettings) && mIsReprocess == other.mIsReprocess - && mReprocessibleSessionId == other.mReprocessibleSessionId; + && mReprocessableSessionId == other.mReprocessableSessionId; } @Override @@ -395,7 +395,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> } mIsReprocess = (in.readInt() == 0) ? false : true; - mReprocessibleSessionId = CameraCaptureSession.SESSION_ID_NONE; + mReprocessableSessionId = CameraCaptureSession.SESSION_ID_NONE; } @Override @@ -450,19 +450,19 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * @param reprocess Indicates whether to create a reprocess capture request. {@code true} * to create a reprocess capture request. {@code false} to create a regular * capture request. - * @param reprocessibleSessionId The ID of the camera capture session this capture is + * @param reprocessableSessionId The ID of the camera capture session this capture is * created for. This is used to validate if the application * submits a reprocess capture request to the same session * where the {@link TotalCaptureResult}, used to create the * reprocess capture, came from. * * @throws IllegalArgumentException If creating a reprocess capture request with an invalid - * reprocessibleSessionId. + * reprocessableSessionId. * @hide */ public Builder(CameraMetadataNative template, boolean reprocess, - int reprocessibleSessionId) { - mRequest = new CaptureRequest(template, reprocess, reprocessibleSessionId); + int reprocessableSessionId) { + mRequest = new CaptureRequest(template, reprocess, reprocessableSessionId); } /** @@ -1275,7 +1275,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * <p>This control (except for MANUAL) is only effective if * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p> * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} - * contains OPAQUE_REPROCESSING or YUV_REPROCESSING. MANUAL will be supported if + * contains PRIVATE_REPROCESSING or YUV_REPROCESSING. MANUAL will be supported if * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains MANUAL_SENSOR. Other intent values are * always supported.</p> * <p><b>Possible values:</b> diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 3dc8970..d931a76 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -1698,7 +1698,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * <p>This control (except for MANUAL) is only effective if * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p> * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} - * contains OPAQUE_REPROCESSING or YUV_REPROCESSING. MANUAL will be supported if + * contains PRIVATE_REPROCESSING or YUV_REPROCESSING. MANUAL will be supported if * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains MANUAL_SENSOR. Other intent values are * always supported.</p> * <p><b>Possible values:</b> diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java index dff6227..d08c52b 100644 --- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java @@ -153,10 +153,10 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { Handler handler) throws CameraAccessException { if (request == null) { throw new IllegalArgumentException("request must not be null"); - } else if (request.isReprocess() && !isReprocessible()) { + } else if (request.isReprocess() && !isReprocessable()) { throw new IllegalArgumentException("this capture session cannot handle reprocess " + "requests"); - } else if (request.isReprocess() && request.getReprocessibleSessionId() != mId) { + } else if (request.isReprocess() && request.getReprocessableSessionId() != mId) { throw new IllegalArgumentException("capture request was created for another session"); } @@ -184,10 +184,10 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { for (CaptureRequest request : requests) { if (request.isReprocess()) { - if (!isReprocessible()) { + if (!isReprocessable()) { throw new IllegalArgumentException("This capture session cannot handle " + "reprocess requests"); - } else if (request.getReprocessibleSessionId() != mId) { + } else if (request.getReprocessableSessionId() != mId) { throw new IllegalArgumentException("Capture request was created for another " + "session"); } @@ -293,7 +293,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { } @Override - public boolean isReprocessible() { + public boolean isReprocessable() { return mInput != null; } diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index e84b46a..4508dc8 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -480,16 +480,16 @@ public class CameraDeviceImpl extends CameraDevice { } @Override - public void createReprocessibleCaptureSession(InputConfiguration inputConfig, + public void createReprocessableCaptureSession(InputConfiguration inputConfig, List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler) throws CameraAccessException { if (DEBUG) { - Log.d(TAG, "createReprocessibleCaptureSession"); + Log.d(TAG, "createReprocessableCaptureSession"); } if (inputConfig == null) { throw new IllegalArgumentException("inputConfig cannot be null when creating a " + - "reprocessible capture session"); + "reprocessable capture session"); } List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size()); for (Surface surface : outputs) { diff --git a/core/java/android/hardware/camera2/params/InputConfiguration.java b/core/java/android/hardware/camera2/params/InputConfiguration.java index dea1c5c..0c642cf 100644 --- a/core/java/android/hardware/camera2/params/InputConfiguration.java +++ b/core/java/android/hardware/camera2/params/InputConfiguration.java @@ -19,11 +19,11 @@ package android.hardware.camera2.params; import android.hardware.camera2.utils.HashCodeHelpers; /** - * Immutable class to store an input configuration that is used to create a reprocessible capture + * Immutable class to store an input configuration that is used to create a reprocessable capture * session. * - * @see CameraDevice#createReprocessibleCaptureSession - * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP + * @see android.hardware.camera2.CameraDevice#createReprocessableCaptureSession + * @see android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP */ public final class InputConfiguration { diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 657beee..338bd76 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -32,7 +32,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback; -import android.security.AndroidKeyStoreProvider; +import android.security.keystore.AndroidKeyStoreProvider; import android.util.Log; import android.util.Slog; diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 0b55998..1cc2d33 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -476,8 +476,18 @@ public final class StrictMode { } /** - * Enable detection of mismatches between defined resource types + * Enables detection of mismatches between defined resource types * and getter calls. + * <p> + * This helps detect accidental type mismatches and potentially + * expensive type conversions when obtaining typed resources. + * <p> + * For example, a strict mode violation would be thrown when + * calling {@link android.content.res.TypedArray#getInt(int, int)} + * on an index that contains a String-type resource. If the string + * value can be parsed as an integer, this method call will return + * a value without crashing; however, the developer should format + * the resource as an integer to avoid unnecessary type conversion. */ public Builder detectResourceMismatches() { return enable(DETECT_RESOURCE_MISMATCH); diff --git a/core/java/android/view/InputEventConsistencyVerifier.java b/core/java/android/view/InputEventConsistencyVerifier.java index c5e4c21..46ef379 100644 --- a/core/java/android/view/InputEventConsistencyVerifier.java +++ b/core/java/android/view/InputEventConsistencyVerifier.java @@ -97,6 +97,9 @@ public final class InputEventConsistencyVerifier { // Set to true if we received hover enter. private boolean mHoverEntered; + // The bitset of buttons which we've received ACTION_BUTTON_PRESS for. + private int mButtonsPressed; + // The current violation message. private StringBuilder mViolationMessage; @@ -148,6 +151,7 @@ public final class InputEventConsistencyVerifier { mTouchEventStreamIsTainted = false; mTouchEventStreamUnhandled = false; mHoverEntered = false; + mButtonsPressed = 0; while (mKeyStateList != null) { final KeyState state = mKeyStateList; @@ -466,6 +470,8 @@ public final class InputEventConsistencyVerifier { final int action = event.getAction(); final int source = event.getSource(); + final int buttonState = event.getButtonState(); + final int actionButton = event.getActionButton(); if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { switch (action) { case MotionEvent.ACTION_HOVER_ENTER: @@ -486,6 +492,62 @@ public final class InputEventConsistencyVerifier { ensureHistorySizeIsZeroForThisAction(event); ensurePointerCountIsOneForThisAction(event); break; + case MotionEvent.ACTION_BUTTON_PRESS: + ensureActionButtonIsNonZeroForThisAction(event); + if ((mButtonsPressed & actionButton) != 0) { + problem("Action button for ACTION_BUTTON_PRESS event is " + + actionButton + ", but it has already been pressed and " + + "has yet to be released."); + } + + mButtonsPressed |= actionButton; + // The system will automatically mirror the stylus buttons onto the button + // state as the old set of generic buttons for apps targeting pre-M. If + // it looks this has happened, go ahead and set the generic buttons as + // pressed to prevent spurious errors. + if (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY && + (buttonState & MotionEvent.BUTTON_SECONDARY) != 0) { + mButtonsPressed |= MotionEvent.BUTTON_SECONDARY; + } else if (actionButton == MotionEvent.BUTTON_STYLUS_SECONDARY && + (buttonState & MotionEvent.BUTTON_TERTIARY) != 0) { + mButtonsPressed |= MotionEvent.BUTTON_TERTIARY; + } + + if (mButtonsPressed != buttonState) { + problem(String.format("Reported button state differs from " + + "expected button state based on press and release events. " + + "Is 0x%08x but expected 0x%08x.", + buttonState, mButtonsPressed)); + } + break; + case MotionEvent.ACTION_BUTTON_RELEASE: + ensureActionButtonIsNonZeroForThisAction(event); + if ((mButtonsPressed & actionButton) != actionButton) { + problem("Action button for ACTION_BUTTON_RELEASE event is " + + actionButton + ", but it was either never pressed or has " + + "already been released."); + } + + mButtonsPressed &= ~actionButton; + // The system will automatically mirror the stylus buttons onto the button + // state as the old set of generic buttons for apps targeting pre-M. If + // it looks this has happened, go ahead and set the generic buttons as + // released to prevent spurious errors. + if (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY && + (buttonState & MotionEvent.BUTTON_SECONDARY) == 0) { + mButtonsPressed &= ~MotionEvent.BUTTON_SECONDARY; + } else if (actionButton == MotionEvent.BUTTON_STYLUS_SECONDARY && + (buttonState & MotionEvent.BUTTON_TERTIARY) == 0) { + mButtonsPressed &= ~MotionEvent.BUTTON_TERTIARY; + } + + if (mButtonsPressed != buttonState) { + problem(String.format("Reported button state differs from " + + "expected button state based on press and release events. " + + "Is 0x%08x but expected 0x%08x.", + buttonState, mButtonsPressed)); + } + break; default: problem("Invalid action for generic pointer event."); break; @@ -563,6 +625,15 @@ public final class InputEventConsistencyVerifier { } } + private void ensureActionButtonIsNonZeroForThisAction(MotionEvent event) { + final int actionButton = event.getActionButton(); + if (actionButton == 0) { + problem("No action button set. Action button should always be non-zero for " + + MotionEvent.actionToString(event.getAction())); + + } + } + private void ensureHistorySizeIsZeroForThisAction(MotionEvent event) { final int historySize = event.getHistorySize(); if (historySize != 0) { diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 5df596a..4394cd8 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -303,6 +303,32 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int ACTION_HOVER_EXIT = 10; /** + * Constant for {@link #getActionMasked}: A button has been pressed. + * + * <p> + * Use {@link #getActionButton()} to get which button was pressed. + * </p><p> + * This action is not a touch event so it is delivered to + * {@link View#onGenericMotionEvent(MotionEvent)} rather than + * {@link View#onTouchEvent(MotionEvent)}. + * </p> + */ + public static final int ACTION_BUTTON_PRESS = 11; + + /** + * Constant for {@link #getActionMasked}: A button has been released. + * + * <p> + * Use {@link #getActionButton()} to get which button was released. + * </p><p> + * This action is not a touch event so it is delivered to + * {@link View#onGenericMotionEvent(MotionEvent)} rather than + * {@link View#onTouchEvent(MotionEvent)}. + * </p> + */ + public static final int ACTION_BUTTON_RELEASE = 12; + + /** * Bits in the action code that represent a pointer index, used with * {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}. Shifting * down by {@link #ACTION_POINTER_INDEX_SHIFT} provides the actual pointer @@ -1174,14 +1200,14 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int BUTTON_PRIMARY = 1 << 0; /** - * Button constant: Secondary button (right mouse button, stylus first button). + * Button constant: Secondary button (right mouse button). * * @see #getButtonState */ public static final int BUTTON_SECONDARY = 1 << 1; /** - * Button constant: Tertiary button (middle mouse button, stylus second button). + * Button constant: Tertiary button (middle mouse button). * * @see #getButtonState */ @@ -1209,6 +1235,20 @@ public final class MotionEvent extends InputEvent implements Parcelable { */ public static final int BUTTON_FORWARD = 1 << 4; + /** + * Button constant: Primary stylus button pressed. + * + * @see #getButtonState + */ + public static final int BUTTON_STYLUS_PRIMARY = 1 << 5; + + /** + * Button constant: Secondary stylus button pressed. + * + * @see #getButtonState + */ + public static final int BUTTON_STYLUS_SECONDARY = 1 << 6; + // NOTE: If you add a new axis here you must also add it to: // native/include/android/input.h @@ -1220,8 +1260,8 @@ public final class MotionEvent extends InputEvent implements Parcelable { "BUTTON_TERTIARY", "BUTTON_BACK", "BUTTON_FORWARD", - "0x00000020", - "0x00000040", + "BUTTON_STYLUS_PRIMARY", + "BUTTON_STYLUS_SECONDARY", "0x00000080", "0x00000100", "0x00000200", @@ -1357,6 +1397,8 @@ public final class MotionEvent extends InputEvent implements Parcelable { private static native void nativeSetEdgeFlags(long nativePtr, int action); private static native int nativeGetMetaState(long nativePtr); private static native int nativeGetButtonState(long nativePtr); + private static native void nativeSetButtonState(long nativePtr, int buttonState); + private static native int nativeGetActionButton(long nativePtr); private static native void nativeOffsetLocation(long nativePtr, float deltaX, float deltaY); private static native float nativeGetXOffset(long nativePtr); private static native float nativeGetYOffset(long nativePtr); @@ -2212,12 +2254,36 @@ public final class MotionEvent extends InputEvent implements Parcelable { * @see #BUTTON_TERTIARY * @see #BUTTON_FORWARD * @see #BUTTON_BACK + * @see #BUTTON_STYLUS_PRIMARY + * @see #BUTTON_STYLUS_SECONDARY */ public final int getButtonState() { return nativeGetButtonState(mNativePtr); } /** + * Sets the bitfield indicating which buttons are pressed. + * + * @see #getButtonState() + * @hide + */ + public final void setButtonState(int buttonState) { + nativeSetButtonState(mNativePtr, buttonState); + } + + /** + * Gets which button has been modified during a press or release action. + * + * For actions other than {@link #ACTION_BUTTON_PRESS} and {@link #ACTION_BUTTON_RELEASE} + * the returned value is undefined. + * + * @see #getButtonState() + */ + public final int getActionButton() { + return nativeGetActionButton(mNativePtr); + } + + /** * Returns the original raw X coordinate of this event. For touch * events on the screen, this is the original location of the event * on the screen, before it had been adjusted for the containing window @@ -3013,6 +3079,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public String toString() { StringBuilder msg = new StringBuilder(); msg.append("MotionEvent { action=").append(actionToString(getAction())); + msg.append(", actionButton=").append(buttonStateToString(getActionButton())); final int pointerCount = getPointerCount(); for (int i = 0; i < pointerCount; i++) { @@ -3066,6 +3133,10 @@ public final class MotionEvent extends InputEvent implements Parcelable { return "ACTION_HOVER_ENTER"; case ACTION_HOVER_EXIT: return "ACTION_HOVER_EXIT"; + case ACTION_BUTTON_PRESS: + return "ACTION_BUTTON_PRESS"; + case ACTION_BUTTON_RELEASE: + return "ACTION_BUTTON_RELEASE"; } int index = (action & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT; switch (action & ACTION_MASK) { @@ -3172,6 +3243,8 @@ public final class MotionEvent extends InputEvent implements Parcelable { * @see #BUTTON_TERTIARY * @see #BUTTON_FORWARD * @see #BUTTON_BACK + * @see #BUTTON_STYLUS_PRIMARY + * @see #BUTTON_STYLUS_SECONDARY */ public final boolean isButtonPressed(int button) { if (button == 0) { @@ -3180,18 +3253,6 @@ public final class MotionEvent extends InputEvent implements Parcelable { return (getButtonState() & button) == button; } - /** - * Checks if a stylus is being used and if the first stylus button is - * pressed. - * - * @return True if the tool is a stylus and if the first stylus button is - * pressed. - * @see #BUTTON_SECONDARY - */ - public final boolean isStylusButtonPressed() { - return (isButtonPressed(BUTTON_SECONDARY) && getToolType(0) == TOOL_TYPE_STYLUS); - } - public static final Parcelable.Creator<MotionEvent> CREATOR = new Parcelable.Creator<MotionEvent>() { public MotionEvent createFromParcel(Parcel in) { diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 85b22fb..d70712a 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -717,6 +717,14 @@ public class TextureView extends View { if (surfaceTexture == null) { throw new NullPointerException("surfaceTexture must not be null"); } + if (surfaceTexture == mSurface) { + throw new IllegalArgumentException("Trying to setSurfaceTexture to " + + "the same SurfaceTexture that's already set."); + } + if (surfaceTexture.isReleased()) { + throw new IllegalArgumentException("Cannot setSurfaceTexture to a " + + "released SurfaceTexture"); + } if (mSurface != null) { mSurface.release(); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 9e16b4b..6ca320a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -5221,8 +5221,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return True if the event was consumed. */ private boolean performStylusActionOnButtonPress(MotionEvent event) { - if (isStylusButtonPressable() && !mInStylusButtonPress - && !mHasPerformedLongPress && event.isStylusButtonPressed()) { + if (isStylusButtonPressable() && !mInStylusButtonPress && !mHasPerformedLongPress + && event.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY)) { if (performStylusButtonPress()) { mInStylusButtonPress = true; setPressed(true, event.getX(), event.getY()); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 7c635b9..4f2a3fa 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -40,6 +40,7 @@ import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.media.AudioManager; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Debug; import android.os.Handler; @@ -2014,6 +2015,7 @@ public final class ViewRootImpl implements ViewParent, mLastWasImTarget = imTarget; InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null && imTarget) { + imm.startGettingWindowFocus(mView); imm.onWindowFocus(mView, mView.findFocus(), mWindowAttributes.softInputMode, !mHasHadWindowFocus, mWindowAttributes.flags); @@ -3320,6 +3322,10 @@ public final class ViewRootImpl implements ViewParent, InputMethodManager imm = InputMethodManager.peekInstance(); if (mView != null) { + if (hasWindowFocus && imm != null && mLastWasImTarget && + !isInLocalFocusMode()) { + imm.startGettingWindowFocus(mView); + } mAttachInfo.mKeyDispatchState.reset(); mView.dispatchWindowFocusChanged(hasWindowFocus); mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus); @@ -5352,7 +5358,7 @@ public final class ViewRootImpl implements ViewParent, //Log.d(TAG, ">>>>>> CALLING relayout"); if (params != null && mOrigWindowType != params.type) { // For compatibility with old apps, don't crash here. - if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { Slog.w(TAG, "Window type can not be changed after " + "the window is added; ignoring change of " + mView); params.type = mOrigWindowType; @@ -5777,6 +5783,7 @@ public final class ViewRootImpl implements ViewParent, void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { + adjustInputEventForCompatibility(event); QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags); // Always enqueue the input event in order, regardless of its time stamp. @@ -5882,6 +5889,19 @@ public final class ViewRootImpl implements ViewParent, recycleQueuedInputEvent(q); } + private void adjustInputEventForCompatibility(InputEvent e) { + if (mTargetSdkVersion < Build.VERSION_CODES.MNC && e instanceof MotionEvent) { + MotionEvent motion = (MotionEvent) e; + final int mask = + MotionEvent.BUTTON_STYLUS_PRIMARY | MotionEvent.BUTTON_STYLUS_SECONDARY; + final int buttonState = motion.getButtonState(); + final int compatButtonState = (buttonState & mask) >> 4; + if (compatButtonState != 0) { + motion.setButtonState(buttonState | compatButtonState); + } + } + } + static boolean isTerminalInputEvent(InputEvent event) { if (event instanceof KeyEvent) { final KeyEvent keyEvent = (KeyEvent)event; diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index c785149..42e6766 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -1011,6 +1011,10 @@ public class AccessibilityNodeInfo implements Parcelable { public void addAction(AccessibilityAction action) { enforceNotSealed(); + addActionUnchecked(action); + } + + private void addActionUnchecked(AccessibilityAction action) { if (action == null) { return; } @@ -2846,9 +2850,9 @@ public class AccessibilityNodeInfo implements Parcelable { addLegacyStandardActions(legacyStandardActions); final int nonLegacyActionCount = actionCount - Integer.bitCount(legacyStandardActions); for (int i = 0; i < nonLegacyActionCount; i++) { - AccessibilityAction action = new AccessibilityAction( + final AccessibilityAction action = new AccessibilityAction( parcel.readInt(), parcel.readCharSequence()); - addAction(action); + addActionUnchecked(action); } } diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 1fb791c..568e160 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -281,7 +281,12 @@ public final class InputMethodManager { boolean mFullscreenMode; // ----------------------------------------------------------- - + + /** + * This is the root view of the overall window that currently has input + * method focus. + */ + View mCurRootView; /** * This is the view that should currently be served by an input method, * regardless of the state of setting that up. @@ -801,6 +806,7 @@ public final class InputMethodManager { * Disconnect any existing input connection, clearing the served view. */ void finishInputLocked() { + mCurRootView = null; mNextServedView = null; if (mServedView != null) { if (DEBUG) Log.v(TAG, "FINISH INPUT: " + mServedView); @@ -1284,9 +1290,10 @@ public final class InputMethodManager { void focusInLocked(View view) { if (DEBUG) Log.v(TAG, "focusIn: " + view); - if (!view.hasWindowFocus()) { - // This is a request from a window that doesn't have window focus, so ignore it. - if (DEBUG) Log.v(TAG, "Not focused window, ignoring"); + if (mCurRootView != view.getRootView()) { + // This is a request from a window that isn't in the window with + // IME focus, so ignore it. + if (DEBUG) Log.v(TAG, "Not IME target window, ignoring"); return; } @@ -1303,9 +1310,16 @@ public final class InputMethodManager { if (DEBUG) Log.v(TAG, "focusOut: " + view + " mServedView=" + mServedView + " winFocus=" + view.hasWindowFocus()); - if (mServedView == view && view.hasWindowFocus()) { - mNextServedView = null; - scheduleCheckFocusLocked(view); + if (mServedView != view) { + // The following code would auto-hide the IME if we end up + // with no more views with focus. This can happen, however, + // whenever we go into touch mode, so it ends up hiding + // at times when we don't really want it to. For now it + // seems better to just turn it all off. + if (false && view.hasWindowFocus()) { + mNextServedView = null; + scheduleCheckFocusLocked(view); + } } } } @@ -1428,6 +1442,13 @@ public final class InputMethodManager { } } + /** @hide */ + public void startGettingWindowFocus(View rootView) { + synchronized (mH) { + mCurRootView = rootView; + } + } + /** * Report the current selection range. * @@ -2135,6 +2156,7 @@ public final class InputMethodManager { + " mBindSequence=" + mBindSequence + " mCurId=" + mCurId); p.println(" mCurMethod=" + mCurMethod); + p.println(" mCurRootView=" + mCurRootView); p.println(" mServedView=" + mServedView); p.println(" mNextServedView=" + mNextServedView); p.println(" mServedConnecting=" + mServedConnecting); diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java index 6fef2d6..ab6a2f9 100644 --- a/core/java/android/webkit/FindActionModeCallback.java +++ b/core/java/android/webkit/FindActionModeCallback.java @@ -154,6 +154,7 @@ public class FindActionModeCallback implements ActionMode.Callback, TextWatcher, } public void showSoftInput() { + mInput.startGettingWindowFocus(mEditText.getRootView()); mInput.focusIn(mEditText); mInput.showSoftInput(mEditText, 0); } diff --git a/core/java/android/webkit/WebResourceError.java b/core/java/android/webkit/WebResourceError.java index 080d174..90693f3 100644 --- a/core/java/android/webkit/WebResourceError.java +++ b/core/java/android/webkit/WebResourceError.java @@ -16,6 +16,8 @@ package android.webkit; +import android.annotation.SystemApi; + /** * Encapsulates information about errors occured during loading of web resources. See * {@link WebViewClient#onReceivedError(WebView, WebResourceRequest, WebResourceError) WebViewClient.onReceivedError(WebView, WebResourceRequest, WebResourceError)} @@ -34,6 +36,16 @@ public abstract class WebResourceError { * and thus can be used for communicating the problem to the user. * * @return The description of the error + * + * Will become abstract after updated WebView.apk will be submitted + * into the Android tree. + */ + public CharSequence getDescription() { return ""; } + + /** + * This class can not be subclassed by applications. + * @hide */ - public abstract String getDescription(); + @SystemApi + public WebResourceError() {} } diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java index a42aaa7..3a925c8 100644 --- a/core/java/android/webkit/WebResourceResponse.java +++ b/core/java/android/webkit/WebResourceResponse.java @@ -20,12 +20,15 @@ import java.io.InputStream; import java.io.StringBufferInputStream; import java.util.Map; +import android.annotation.SystemApi; + /** * Encapsulates a resource response. Applications can return an instance of this * class from {@link WebViewClient#shouldInterceptRequest} to provide a custom * response when the WebView requests a particular resource. */ public class WebResourceResponse extends WebResourceResponseBase { + private boolean mImmutable; private String mMimeType; private String mEncoding; private int mStatusCode; @@ -80,13 +83,15 @@ public class WebResourceResponse extends WebResourceResponseBase { * @param mimeType The resource response's MIME type */ public void setMimeType(String mimeType) { + checkImmutable(); mMimeType = mimeType; } /** - * {@inheritDoc} + * Gets the resource response's MIME type. + * + * @return The resource response's MIME type */ - @Override public String getMimeType() { return mMimeType; } @@ -98,13 +103,15 @@ public class WebResourceResponse extends WebResourceResponseBase { * @param encoding The resource response's encoding */ public void setEncoding(String encoding) { + checkImmutable(); mEncoding = encoding; } /** - * {@inheritDoc} + * Gets the resource response's encoding. + * + * @return The resource response's encoding */ - @Override public String getEncoding() { return mEncoding; } @@ -118,6 +125,7 @@ public class WebResourceResponse extends WebResourceResponseBase { * and not empty. */ public void setStatusCodeAndReasonPhrase(int statusCode, String reasonPhrase) { + checkImmutable(); if (statusCode < 100) throw new IllegalArgumentException("statusCode can't be less than 100."); if (statusCode > 599) @@ -140,17 +148,19 @@ public class WebResourceResponse extends WebResourceResponseBase { } /** - * {@inheritDoc} + * Gets the resource response's status code. + * + * @return The resource response's status code. */ - @Override public int getStatusCode() { return mStatusCode; } /** - * {@inheritDoc} + * Gets the description of the resource response's status code. + * + * @return The description of the resource response's status code. */ - @Override public String getReasonPhrase() { return mReasonPhrase; } @@ -161,13 +171,15 @@ public class WebResourceResponse extends WebResourceResponseBase { * @param headers Mapping of header name -> header value. */ public void setResponseHeaders(Map<String, String> headers) { + checkImmutable(); mResponseHeaders = headers; } /** - * {@inheritDoc} + * Gets the headers for the resource response. + * + * @return The headers for the resource response. */ - @Override public Map<String, String> getResponseHeaders() { return mResponseHeaders; } @@ -180,6 +192,7 @@ public class WebResourceResponse extends WebResourceResponseBase { * StringBufferInputStream. */ public void setData(InputStream data) { + checkImmutable(); // If data is (or is a subclass of) StringBufferInputStream if (data != null && StringBufferInputStream.class.isAssignableFrom(data.getClass())) { throw new IllegalArgumentException("StringBufferInputStream is deprecated and must " + @@ -189,10 +202,32 @@ public class WebResourceResponse extends WebResourceResponseBase { } /** - * {@inheritDoc} + * Gets the input stream that provides the resource response's data. + * + * @return The input stream that provides the resource response's data */ - @Override public InputStream getData() { return mInputStream; } + + /** + * The internal version of the constructor that doesn't perform arguments checks. + * @hide + */ + @SystemApi + public WebResourceResponse(boolean immutable, String mimeType, String encoding, int statusCode, + String reasonPhrase, Map<String, String> responseHeaders, InputStream data) { + mImmutable = immutable; + mMimeType = mimeType; + mEncoding = encoding; + mStatusCode = statusCode; + mReasonPhrase = reasonPhrase; + mResponseHeaders = responseHeaders; + mInputStream = data; + } + + private void checkImmutable() { + if (mImmutable) + throw new IllegalStateException("This WebResourceResponse instance is immutable"); + } } diff --git a/core/java/android/webkit/WebResourceResponseBase.java b/core/java/android/webkit/WebResourceResponseBase.java index cffde82..69eb397 100644 --- a/core/java/android/webkit/WebResourceResponseBase.java +++ b/core/java/android/webkit/WebResourceResponseBase.java @@ -16,53 +16,9 @@ package android.webkit; -import java.io.InputStream; -import java.util.Map; - /** - * Encapsulates a resource response received from the server. - * This is an abstract class used by WebView callbacks. + * This class will be deleted after updated WebView.apk will be submitted + * into the Android tree. */ public abstract class WebResourceResponseBase { - /** - * Gets the resource response's MIME type. - * - * @return The resource response's MIME type - */ - public abstract String getMimeType(); - - /** - * Gets the resource response's encoding. - * - * @return The resource response's encoding - */ - public abstract String getEncoding(); - - /** - * Gets the resource response's status code. - * - * @return The resource response's status code. - */ - public abstract int getStatusCode(); - - /** - * Gets the description of the resource response's status code. - * - * @return The description of the resource response's status code. - */ - public abstract String getReasonPhrase(); - - /** - * Gets the headers for the resource response. - * - * @return The headers for the resource response. - */ - public abstract Map<String, String> getResponseHeaders(); - - /** - * Gets the input stream that provides the resource response's data. - * - * @return The input stream that provides the resource response's data - */ - public abstract InputStream getData(); } diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java index 3a40de6..feed2b8 100644 --- a/core/java/android/webkit/WebViewClient.java +++ b/core/java/android/webkit/WebViewClient.java @@ -233,11 +233,20 @@ public class WebViewClient { public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { if (request.isForMainFrame()) { onReceivedError(view, - error.getErrorCode(), error.getDescription(), request.getUrl().toString()); + error.getErrorCode(), error.getDescription().toString(), + request.getUrl().toString()); } } /** + * This method will be deleted after updated WebView.apk will be submitted + * into the Android tree. + */ + public void onReceivedHttpError( + WebView view, WebResourceRequest request, WebResourceResponseBase errorResponse) { + } + + /** * Notify the host application that an HTTP error has been received from the server while * loading a resource. HTTP errors have status codes >= 400. This callback will be called * for any resource (iframe, image, etc), not just for the main page. Thus, it is recommended to @@ -248,7 +257,7 @@ public class WebViewClient { * @param errorResponse Information about the error occured. */ public void onReceivedHttpError( - WebView view, WebResourceRequest request, WebResourceResponseBase errorResponse) { + WebView view, WebResourceRequest request, WebResourceResponse errorResponse) { } /** diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java index 51174c3..75c857c 100644 --- a/core/java/android/widget/ActivityChooserModel.java +++ b/core/java/android/widget/ActivityChooserModel.java @@ -40,6 +40,7 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -991,7 +992,7 @@ public class ActivityChooserModel extends DataSetObservable { } try { XmlPullParser parser = Xml.newPullParser(); - parser.setInput(fis, null); + parser.setInput(fis, StandardCharsets.UTF_8.name()); int type = XmlPullParser.START_DOCUMENT; while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { @@ -1074,7 +1075,7 @@ public class ActivityChooserModel extends DataSetObservable { try { serializer.setOutput(fos, null); - serializer.startDocument("UTF-8", true); + serializer.startDocument(StandardCharsets.UTF_8.name(), true); serializer.startTag(null, TAG_HISTORICAL_RECORDS); final int recordCount = historicalRecords.size(); diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 814882a..a1194f7 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -209,6 +209,10 @@ public class Editor { // Set when this TextView gained focus with some text selected. Will start selection mode. boolean mCreatedWithASelection; + boolean mDoubleTap = false; + + private Runnable mSelectionModeWithoutSelectionRunnable; + // The span controller helps monitoring the changes to which the Editor needs to react: // - EasyEditSpans, for which we have some UI to display on attach and on hide // - SelectionSpans, for which we need to call updateSelection if an IME is attached @@ -286,6 +290,13 @@ public class Editor { mUndoManager.redo(owners, 1); // Redo 1 action. } + void replace() { + int middle = (mTextView.getSelectionStart() + mTextView.getSelectionEnd()) / 2; + stopSelectionActionMode(); + Selection.setSelection((Spannable) mTextView.getText(), middle); + showSuggestions(); + } + void onAttachedToWindow() { if (mShowErrorAfterAttach) { showError(); @@ -342,6 +353,11 @@ public class Editor { mTextView.removeCallbacks(mShowSuggestionRunnable); } + // Cancel the single tap delayed runnable. + if (mSelectionModeWithoutSelectionRunnable != null) { + mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable); + } + destroyDisplayListsData(); if (mSpellChecker != null) { @@ -1799,6 +1815,7 @@ public class Editor { // When the cursor moves, the word that was typed may need spell check mSpellChecker.onSelectionChanged(); } + if (!extractedTextModeWillBeStarted()) { if (isCursorInsideEasyCorrectionSpan()) { mShowSuggestionRunnable = new Runnable() { @@ -3117,10 +3134,6 @@ public class Editor { mCustomSelectionActionModeCallback.onActionItemClicked(mode, item)) { return true; } - if (item.getItemId() == TextView.ID_REPLACE) { - onReplace(); - return true; - } return mTextView.onTextContextMenuItem(item.getItemId()); } @@ -3194,13 +3207,6 @@ public class Editor { } } - private void onReplace() { - int middle = (mTextView.getSelectionStart() + mTextView.getSelectionEnd()) / 2; - stopSelectionActionMode(); - Selection.setSelection((Spannable) mTextView.getText(), middle); - showSuggestions(); - } - /** * A listener to call {@link InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo)} * while the input method is requesting the cursor/anchor position. Does nothing as long as @@ -3726,9 +3732,27 @@ public class Editor { super.show(); final long durationSinceCutOrCopy = - SystemClock.uptimeMillis() - TextView.LAST_CUT_OR_COPY_TIME; - if (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION) { - startSelectionActionModeWithoutSelection(); + SystemClock.uptimeMillis() - TextView.sLastCutCopyOrTextChangedTime; + + // Cancel the single tap delayed runnable. + if (mDoubleTap && mSelectionModeWithoutSelectionRunnable != null) { + mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable); + } + + // Prepare and schedule the single tap runnable to run exactly after the double tap + // timeout has passed. + if (!mDoubleTap && (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION)) { + if (mSelectionModeWithoutSelectionRunnable == null) { + mSelectionModeWithoutSelectionRunnable = new Runnable() { + public void run() { + startSelectionActionModeWithoutSelection(); + } + }; + } + + mTextView.postDelayed( + mSelectionModeWithoutSelectionRunnable, + ViewConfiguration.getDoubleTapTimeout() + 1); } hideAfterDelay(); @@ -3855,8 +3879,8 @@ public class Editor { private class SelectionStartHandleView extends HandleView { // Indicates whether the cursor is making adjustments within a word. private boolean mInWord = false; - // Offset to track difference between touch and word boundary. - protected int mTouchWordOffset; + // Difference between touch position and word boundary position. + private float mTouchWordDelta; public SelectionStartHandleView(Drawable drawableLtr, Drawable drawableRtl) { super(drawableLtr, drawableRtl); @@ -3908,18 +3932,36 @@ public class Editor { offset = mPreviousOffset; } } - mTouchWordOffset = Math.max(trueOffset - offset, 0); - positionCursor = true; - } else if (offset - mTouchWordOffset > mPreviousOffset || currLine > mPrevLine) { - // User is shrinking the selection. - if (currLine > mPrevLine) { - // We're on a different line, so we'll snap to word boundaries. - offset = start; - mTouchWordOffset = Math.max(trueOffset - offset, 0); + final Layout layout = mTextView.getLayout(); + if (layout != null && offset < trueOffset) { + final float adjustedX = layout.getPrimaryHorizontal(offset); + mTouchWordDelta = + mTextView.convertToLocalHorizontalCoordinate(x) - adjustedX; } else { - offset -= mTouchWordOffset; + mTouchWordDelta = 0.0f; } positionCursor = true; + } else { + final int adjustedOffset = + mTextView.getOffsetAtCoordinate(currLine, x - mTouchWordDelta); + if (adjustedOffset > mPreviousOffset || currLine > mPrevLine) { + // User is shrinking the selection. + if (currLine > mPrevLine) { + // We're on a different line, so we'll snap to word boundaries. + offset = start; + final Layout layout = mTextView.getLayout(); + if (layout != null && offset < trueOffset) { + final float adjustedX = layout.getPrimaryHorizontal(offset); + mTouchWordDelta = + mTextView.convertToLocalHorizontalCoordinate(x) - adjustedX; + } else { + mTouchWordDelta = 0.0f; + } + } else { + offset = adjustedOffset; + } + positionCursor = true; + } } // Handles can not cross and selection is at least one character. @@ -3934,7 +3976,7 @@ public class Editor { } else { offset = alteredOffset; } - mTouchWordOffset = 0; + mTouchWordDelta = 0.0f; } mInWord = !getWordIteratorWithText().isBoundary(offset); positionAtCursorOffset(offset, false); @@ -3946,7 +3988,7 @@ public class Editor { boolean superResult = super.onTouchEvent(event); if (event.getActionMasked() == MotionEvent.ACTION_UP) { // Reset the touch word offset when the user has lifted their finger. - mTouchWordOffset = 0; + mTouchWordDelta = 0.0f; } return superResult; } @@ -3955,8 +3997,8 @@ public class Editor { private class SelectionEndHandleView extends HandleView { // Indicates whether the cursor is making adjustments within a word. private boolean mInWord = false; - // Offset to track difference between touch and word boundary. - protected int mTouchWordOffset; + // Difference between touch position and word boundary position. + private float mTouchWordDelta; public SelectionEndHandleView(Drawable drawableLtr, Drawable drawableRtl) { super(drawableLtr, drawableRtl); @@ -4008,18 +4050,36 @@ public class Editor { offset = mPreviousOffset; } } - mTouchWordOffset = Math.max(offset - trueOffset, 0); - positionCursor = true; - } else if (offset + mTouchWordOffset < mPreviousOffset || currLine < mPrevLine) { - // User is shrinking the selection. - if (currLine < mPrevLine) { - // We're on a different line, so we'll snap to word boundaries. - offset = end; - mTouchWordOffset = Math.max(offset - trueOffset, 0); + final Layout layout = mTextView.getLayout(); + if (layout != null && offset > trueOffset) { + final float adjustedX = layout.getPrimaryHorizontal(offset); + mTouchWordDelta = + adjustedX - mTextView.convertToLocalHorizontalCoordinate(x); } else { - offset += mTouchWordOffset; + mTouchWordDelta = 0.0f; } positionCursor = true; + } else { + final int adjustedOffset = + mTextView.getOffsetAtCoordinate(currLine, x + mTouchWordDelta); + if (adjustedOffset < mPreviousOffset || currLine < mPrevLine) { + // User is shrinking the selection. + if (currLine < mPrevLine) { + // We're on a different line, so we'll snap to word boundaries. + offset = end; + final Layout layout = mTextView.getLayout(); + if (layout != null && offset > trueOffset) { + final float adjustedX = layout.getPrimaryHorizontal(offset); + mTouchWordDelta = + adjustedX - mTextView.convertToLocalHorizontalCoordinate(x); + } else { + mTouchWordDelta = 0.0f; + } + } else { + offset = adjustedOffset; + } + positionCursor = true; + } } if (positionCursor) { @@ -4034,7 +4094,7 @@ public class Editor { } else { offset = Math.min(alteredOffset, length); } - mTouchWordOffset = 0; + mTouchWordDelta = 0.0f; } mInWord = !getWordIteratorWithText().isBoundary(offset); positionAtCursorOffset(offset, false); @@ -4046,7 +4106,7 @@ public class Editor { boolean superResult = super.onTouchEvent(event); if (event.getActionMasked() == MotionEvent.ACTION_UP) { // Reset the touch word offset when the user has lifted their finger. - mTouchWordOffset = 0; + mTouchWordDelta = 0.0f; } return superResult; } @@ -4081,6 +4141,10 @@ public class Editor { public void show() { getHandle().show(); + + if (mSelectionModifierCursorController != null) { + mSelectionModifierCursorController.hide(); + } } public void hide() { @@ -4122,8 +4186,6 @@ public class Editor { // The offsets of that last touch down event. Remembered to start selection there. private int mMinTouchOffset, mMaxTouchOffset; - // Double tap detection - private long mPreviousTapUpTime = 0; private float mDownPositionX, mDownPositionY; private boolean mGestureStayedInTapRegion; @@ -4205,8 +4267,7 @@ public class Editor { // Double tap detection if (mGestureStayedInTapRegion) { - long duration = SystemClock.uptimeMillis() - mPreviousTapUpTime; - if (duration <= ViewConfiguration.getDoubleTapTimeout()) { + if (mDoubleTap) { final float deltaX = x - mDownPositionX; final float deltaY = y - mDownPositionY; final float distanceSquared = deltaX * deltaX + deltaY * deltaY; @@ -4315,7 +4376,6 @@ public class Editor { break; case MotionEvent.ACTION_UP: - mPreviousTapUpTime = SystemClock.uptimeMillis(); if (mDragAcceleratorActive) { // No longer dragging to select text, let the parent intercept events. mTextView.getParent().requestDisallowInterceptTouchEvent(false); diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 05059bc..73a873a 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -36,8 +36,10 @@ import android.graphics.RectF; import android.graphics.Xfermode; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Build; +import android.os.Handler; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; @@ -462,6 +464,21 @@ public class ImageView extends View { } /** + * Sets the content of this ImageView to the specified Icon. + * + * <p class="note">Depending on the Icon type, this may do Bitmap reading and decoding + * on the UI thread, which can cause UI jank. If that's a concern, consider using + * {@link Icon#loadDrawableAsync(Context, Icon.OnDrawableLoadedListener, Handler)} + * and then {@link #setImageDrawable(android.graphics.drawable.Drawable)} instead.</p> + * + * @param icon an Icon holding the desired image + */ + @android.view.RemotableViewMethod + public void setImageIcon(Icon icon) { + setImageDrawable(icon.loadDrawable(mContext)); + } + + /** * Applies a tint to the image drawable. Does not modify the current tint * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. * <p> diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index a10be11..dc75fd0 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -35,6 +35,7 @@ import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -1072,6 +1073,7 @@ public class RemoteViews implements Parcelable, Filter { static final int BUNDLE = 13; static final int INTENT = 14; static final int COLOR_STATE_LIST = 15; + static final int ICON = 16; String methodName; int type; @@ -1150,6 +1152,10 @@ public class RemoteViews implements Parcelable, Filter { this.value = ColorStateList.CREATOR.createFromParcel(in); } break; + case ICON: + if (in.readInt() != 0) { + this.value = Icon.CREATOR.createFromParcel(in); + } default: break; } @@ -1225,6 +1231,13 @@ public class RemoteViews implements Parcelable, Filter { if (this.value != null) { ((ColorStateList)this.value).writeToParcel(out, flags); } + break; + case ICON: + out.writeInt(this.value != null ? 1 : 0); + if (this.value != null) { + ((Icon)this.value).writeToParcel(out, flags); + } + break; default: break; } @@ -1262,6 +1275,8 @@ public class RemoteViews implements Parcelable, Filter { return Intent.class; case COLOR_STATE_LIST: return ColorStateList.class; + case ICON: + return Icon.class; default: return null; } @@ -2082,6 +2097,16 @@ public class RemoteViews implements Parcelable, Filter { } /** + * Equivalent to calling ImageView.setImageIcon + * + * @param viewId The id of the view whose bitmap should change + * @param icon The new Icon for the ImageView + */ + public void setImageViewIcon(int viewId, Icon icon) { + setIcon(viewId, "setImageIcon", icon); + } + + /** * Equivalent to calling AdapterView.setEmptyView * * @param viewId The id of the view on which to set the empty view @@ -2519,6 +2544,17 @@ public class RemoteViews implements Parcelable, Filter { } /** + * Call a method taking one Icon on a view in the layout for this RemoteViews. + * + * @param viewId The id of the view on which to call the method. + * @param methodName The name of the method to call. + * @param value The {@link android.graphics.drawable.Icon} to pass the method. + */ + public void setIcon(int viewId, String methodName, Icon value) { + addAction(new ReflectionAction(viewId, methodName, ReflectionAction.ICON, value)); + } + + /** * Equivalent to calling View.setContentDescription(CharSequence). * * @param viewId The id of the view whose content description should change. diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index ee8e5c4..5acd79f 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -292,8 +292,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // New state used to change background based on whether this TextView is multiline. private static final int[] MULTILINE_STATE_SET = { R.attr.state_multiline }; - // System wide time for last cut or copy action. - static long LAST_CUT_OR_COPY_TIME; + // System wide time for last cut, copy or text changed action. + static long sLastCutCopyOrTextChangedTime; /** * @hide @@ -599,6 +599,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private final Paint mHighlightPaint; private boolean mHighlightPathBogus = true; + private boolean mFirstTouch = false; + private long mLastTouchUpTime = 0; + // Although these fields are specific to editable text, they are not added to Editor because // they are defined by the TextView's style and are theme-dependent. int mCursorDrawableRes; @@ -8005,6 +8008,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * through a thunk. */ void sendAfterTextChanged(Editable text) { + sLastCutCopyOrTextChangedTime = 0; + if (mListeners != null) { final ArrayList<TextWatcher> list = mListeners; final int count = list.size(); @@ -8277,6 +8282,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public boolean onTouchEvent(MotionEvent event) { final int action = event.getActionMasked(); + if (mEditor != null && action == MotionEvent.ACTION_DOWN) { + // Detect double tap and inform the Editor. + if (mFirstTouch && (SystemClock.uptimeMillis() - mLastTouchUpTime) <= + ViewConfiguration.getDoubleTapTimeout()) { + mEditor.mDoubleTap = true; + mFirstTouch = false; + } else { + mEditor.mDoubleTap = false; + mFirstTouch = true; + } + } + + if (action == MotionEvent.ACTION_UP) { + mLastTouchUpTime = SystemClock.uptimeMillis(); + } + if (mEditor != null) { mEditor.onTouchEvent(event); @@ -9051,6 +9072,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener stopSelectionActionMode(); return true; + case ID_REPLACE: + if (mEditor != null) { + mEditor.replace(); + } + return true; + case ID_SHARE: shareSelectedText(); return true; @@ -9285,7 +9312,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } stopSelectionActionMode(); - LAST_CUT_OR_COPY_TIME = 0; + sLastCutCopyOrTextChangedTime = 0; } } @@ -9305,7 +9332,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener ClipboardManager clipboard = (ClipboardManager) getContext(). getSystemService(Context.CLIPBOARD_SERVICE); clipboard.setPrimaryClip(clip); - LAST_CUT_OR_COPY_TIME = SystemClock.uptimeMillis(); + sLastCutCopyOrTextChangedTime = SystemClock.uptimeMillis(); } /** |
