diff options
Diffstat (limited to 'core/java')
116 files changed, 2931 insertions, 1432 deletions
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java index dbc9051..3e4a66d 100644 --- a/core/java/android/accounts/AbstractAccountAuthenticator.java +++ b/core/java/android/accounts/AbstractAccountAuthenticator.java @@ -108,6 +108,14 @@ import java.util.Arrays; public abstract class AbstractAccountAuthenticator { private static final String TAG = "AccountAuthenticator"; + /** + * Bundle key used for the {@code long} expiration time (in millis from the unix epoch) of the + * associated auth token. + * + * @see #getAuthToken + */ + public static final String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry"; + private final Context mContext; public AbstractAccountAuthenticator(Context context) { @@ -115,6 +123,7 @@ public abstract class AbstractAccountAuthenticator { } private class Transport extends IAccountAuthenticator.Stub { + @Override public void addAccount(IAccountAuthenticatorResponse response, String accountType, String authTokenType, String[] features, Bundle options) throws RemoteException { @@ -140,6 +149,7 @@ public abstract class AbstractAccountAuthenticator { } } + @Override public void confirmCredentials(IAccountAuthenticatorResponse response, Account account, Bundle options) throws RemoteException { if (Log.isLoggable(TAG, Log.VERBOSE)) { @@ -162,6 +172,7 @@ public abstract class AbstractAccountAuthenticator { } } + @Override public void getAuthTokenLabel(IAccountAuthenticatorResponse response, String authTokenType) throws RemoteException { @@ -184,6 +195,7 @@ public abstract class AbstractAccountAuthenticator { } } + @Override public void getAuthToken(IAccountAuthenticatorResponse response, Account account, String authTokenType, Bundle loginOptions) throws RemoteException { @@ -209,6 +221,7 @@ public abstract class AbstractAccountAuthenticator { } } + @Override public void updateCredentials(IAccountAuthenticatorResponse response, Account account, String authTokenType, Bundle loginOptions) throws RemoteException { if (Log.isLoggable(TAG, Log.VERBOSE)) { @@ -234,6 +247,7 @@ public abstract class AbstractAccountAuthenticator { } } + @Override public void editProperties(IAccountAuthenticatorResponse response, String accountType) throws RemoteException { checkBinderPermission(); @@ -248,6 +262,7 @@ public abstract class AbstractAccountAuthenticator { } } + @Override public void hasFeatures(IAccountAuthenticatorResponse response, Account account, String[] features) throws RemoteException { checkBinderPermission(); @@ -262,6 +277,7 @@ public abstract class AbstractAccountAuthenticator { } } + @Override public void getAccountRemovalAllowed(IAccountAuthenticatorResponse response, Account account) throws RemoteException { checkBinderPermission(); @@ -276,6 +292,7 @@ public abstract class AbstractAccountAuthenticator { } } + @Override public void getAccountCredentialsForCloning(IAccountAuthenticatorResponse response, Account account) throws RemoteException { checkBinderPermission(); @@ -291,6 +308,7 @@ public abstract class AbstractAccountAuthenticator { } } + @Override public void addAccountFromCredentials(IAccountAuthenticatorResponse response, Account account, Bundle accountCredentials) throws RemoteException { @@ -410,21 +428,42 @@ public abstract class AbstractAccountAuthenticator { public abstract Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException; + /** - * Gets the authtoken for an account. + * Gets an authtoken for an account. + * + * If not {@code null}, the resultant {@link Bundle} will contain different sets of keys + * depending on whether a token was successfully issued and, if not, whether one + * could be issued via some {@link android.app.Activity}. + * <p> + * If a token cannot be provided without some additional activity, the Bundle should contain + * {@link AccountManager#KEY_INTENT} with an associated {@link Intent}. On the other hand, if + * there is no such activity, then a Bundle containing + * {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} should be + * returned. + * <p> + * If a token can be successfully issued, the implementation should return the + * {@link AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of the + * account associated with the token as well as the {@link AccountManager#KEY_AUTHTOKEN}. In + * addition {@link AbstractAccountAuthenticator} implementations that declare themselves + * {@code android:customTokens=true} may also provide a non-negative {@link + * #KEY_CUSTOM_TOKEN_EXPIRY} long value containing the expiration timestamp of the expiration + * time (in millis since the unix epoch). + * <p> + * Implementers should assume that tokens will be cached on the basis of account and + * authTokenType. The system may ignore the contents of the supplied options Bundle when + * determining to re-use a cached token. Furthermore, implementers should assume a supplied + * expiration time will be treated as non-binding advice. + * <p> + * Finally, note that for android:customTokens=false authenticators, tokens are cached + * indefinitely until some client calls {@link + * AccountManager#invalidateAuthToken(String,String)}. + * * @param response to send the result back to the AccountManager, will never be null * @param account the account whose credentials are to be retrieved, will never be null * @param authTokenType the type of auth token to retrieve, will never be null * @param options a Bundle of authenticator-specific options, may be null - * @return a Bundle result or null if the result is to be returned via the response. The result - * will contain either: - * <ul> - * <li> {@link AccountManager#KEY_INTENT}, or - * <li> {@link AccountManager#KEY_ACCOUNT_NAME}, {@link AccountManager#KEY_ACCOUNT_TYPE}, - * and {@link AccountManager#KEY_AUTHTOKEN}, or - * <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to - * indicate an error - * </ul> + * @return a Bundle result or null if the result is to be returned via the response. * @throws NetworkErrorException if the authenticator could not honor the request due to a * network error */ @@ -518,6 +557,7 @@ public abstract class AbstractAccountAuthenticator { public Bundle getAccountCredentialsForCloning(final AccountAuthenticatorResponse response, final Account account) throws NetworkErrorException { new Thread(new Runnable() { + @Override public void run() { Bundle result = new Bundle(); result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); @@ -543,6 +583,7 @@ public abstract class AbstractAccountAuthenticator { Account account, Bundle accountCredentials) throws NetworkErrorException { new Thread(new Runnable() { + @Override public void run() { Bundle result = new Bundle(); result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 02e0d5b..e4def1e 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2193,7 +2193,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM data.enforceInterface(IActivityManager.descriptor); IBinder token = data.readStrongBinder(); Bundle extras = data.readBundle(); - reportAssistContextExtras(token, extras); + AssistStructure structure = AssistStructure.CREATOR.createFromParcel(data); + AssistContent content = AssistContent.CREATOR.createFromParcel(data); + reportAssistContextExtras(token, extras, structure, content); reply.writeNoException(); return true; } @@ -5359,13 +5361,15 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } - public void reportAssistContextExtras(IBinder token, Bundle extras) - throws RemoteException { + public void reportAssistContextExtras(IBinder token, Bundle extras, AssistStructure structure, + AssistContent content) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(token); data.writeBundle(extras); + structure.writeToParcel(data, 0); + content.writeToParcel(data, 0); mRemote.transact(REPORT_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index cb436b5..2a98b6c 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -2562,15 +2562,18 @@ public final class ActivityThread { public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) { Bundle data = new Bundle(); + AssistStructure structure = null; + AssistContent content = new AssistContent(); ActivityClientRecord r = mActivities.get(cmd.activityToken); if (r != null) { r.activity.getApplication().dispatchOnProvideAssistData(r.activity, data); r.activity.onProvideAssistData(data); if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL) { - data.putParcelable(AssistStructure.ASSIST_KEY, new AssistStructure(r.activity)); - AssistContent content = new AssistContent(); + structure = new AssistStructure(r.activity); Intent activityIntent = r.activity.getIntent(); - if (activityIntent != null) { + if (activityIntent != null && (r.window == null || + (r.window.getAttributes().flags + & WindowManager.LayoutParams.FLAG_SECURE) == 0)) { Intent intent = new Intent(activityIntent); intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)); @@ -2580,15 +2583,14 @@ public final class ActivityThread { content.setIntent(new Intent()); } r.activity.onProvideAssistContent(content); - data.putParcelable(AssistContent.ASSIST_KEY, content); } } - if (data.isEmpty()) { - data = null; + if (structure == null) { + structure = new AssistStructure(); } IActivityManager mgr = ActivityManagerNative.getDefault(); try { - mgr.reportAssistContextExtras(cmd.requestToken, data); + mgr.reportAssistContextExtras(cmd.requestToken, data, structure, content); } catch (RemoteException e) { } } diff --git a/core/java/android/app/AssistContent.java b/core/java/android/app/AssistContent.java index cb1a3f5..f271af1 100644 --- a/core/java/android/app/AssistContent.java +++ b/core/java/android/app/AssistContent.java @@ -18,6 +18,7 @@ package android.app; import android.content.ClipData; import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -30,14 +31,17 @@ import android.os.Parcelable; public class AssistContent implements Parcelable { private Intent mIntent; private ClipData mClipData; + private Uri mUri; /** + * @hide * Key name this data structure is stored in the Bundle generated by * {@link Activity#onProvideAssistData}. */ public static final String ASSIST_KEY = "android:assist_content"; /** + * @hide * Retrieve the framework-generated AssistContent that is stored within * the Bundle filled in by {@link Activity#onProvideAssistContent}. */ @@ -56,6 +60,13 @@ public class AssistContent implements Parcelable { */ public void setIntent(Intent intent) { mIntent = intent; + setWebUri(null); + if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) { + Uri uri = intent.getData(); + if ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) { + setWebUri(uri); + } + } } /** @@ -81,6 +92,30 @@ public class AssistContent implements Parcelable { return mClipData; } + /** + * Set a web URI associated with the current data being shown to the user. + * This URI could be opened in a web browser, or in the app as an + * {@link Intent#ACTION_VIEW} Intent, to show the same data that is currently + * being displayed by it. The URI here should be something that is transportable + * off the device into other environments to acesss the same data as is currently + * being shown in the app; if the app does not have such a representation, it should + * leave the null and only report the local intent and clip data. + * + * <p>This will be automatically populated for you from {@link #setIntent} if that Intent + * is an {@link Intent#ACTION_VIEW} of a web (http or https scheme) URI.</p> + */ + public void setWebUri(Uri uri) { + mUri = uri; + } + + /** + * Return the content's web URI as per {@link #setWebUri(android.net.Uri)}, or null if + * there is none. + */ + public Uri getWebUri() { + return mUri; + } + AssistContent(Parcel in) { if (in.readInt() != 0) { mIntent = Intent.CREATOR.createFromParcel(in); @@ -88,6 +123,9 @@ public class AssistContent implements Parcelable { if (in.readInt() != 0) { mClipData = ClipData.CREATOR.createFromParcel(in); } + if (in.readInt() != 0) { + mUri = Uri.CREATOR.createFromParcel(in); + } } @Override @@ -109,6 +147,12 @@ public class AssistContent implements Parcelable { } else { dest.writeInt(0); } + if (mUri != null) { + dest.writeInt(1); + mUri.writeToParcel(dest, flags); + } else { + dest.writeInt(0); + } } public static final Parcelable.Creator<AssistContent> CREATOR diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java index b703b0e..ca47a5e 100644 --- a/core/java/android/app/AssistStructure.java +++ b/core/java/android/app/AssistStructure.java @@ -42,13 +42,13 @@ import java.util.ArrayList; /** * Assist data automatically created by the platform's implementation - * of {@link Activity#onProvideAssistData}. Retrieve it from the assist - * data with {@link #getAssistStructure(android.os.Bundle)}. + * of {@link Activity#onProvideAssistData}. */ final public class AssistStructure implements Parcelable { static final String TAG = "AssistStructure"; /** + * @hide * Key name this data structure is stored in the Bundle generated by * {@link Activity#onProvideAssistData}. */ @@ -607,35 +607,7 @@ final public class AssistStructure implements Parcelable { } @Override - public void setTextPaint(TextPaint paint) { - ViewNodeText t = getNodeText(); - t.mTextColor = paint.getColor(); - t.mTextBackgroundColor = paint.bgColor; - t.mTextSize = paint.getTextSize(); - t.mTextStyle = 0; - Typeface tf = paint.getTypeface(); - if (tf != null) { - if (tf.isBold()) { - t.mTextStyle |= ViewNode.TEXT_STYLE_BOLD; - } - if (tf.isItalic()) { - t.mTextStyle |= ViewNode.TEXT_STYLE_ITALIC; - } - } - int pflags = paint.getFlags(); - if ((pflags& Paint.FAKE_BOLD_TEXT_FLAG) != 0) { - t.mTextStyle |= ViewNode.TEXT_STYLE_BOLD; - } - if ((pflags& Paint.UNDERLINE_TEXT_FLAG) != 0) { - t.mTextStyle |= ViewNode.TEXT_STYLE_UNDERLINE; - } - if ((pflags& Paint.STRIKE_THRU_TEXT_FLAG) != 0) { - t.mTextStyle |= ViewNode.TEXT_STYLE_STRIKE_THRU; - } - } - - @Override - public void setTextStyle(int size, int fgColor, int bgColor, int style) { + public void setTextStyle(float size, int fgColor, int bgColor, int style) { ViewNodeText t = getNodeText(); t.mTextColor = fgColor; t.mTextBackgroundColor = bgColor; @@ -741,6 +713,11 @@ final public class AssistStructure implements Parcelable { } } + AssistStructure() { + mHaveData = true; + mActivityComponent = null; + } + AssistStructure(Parcel in) { mReceiveChannel = in.readStrongBinder(); } @@ -811,6 +788,7 @@ final public class AssistStructure implements Parcelable { } /** + * @hide * Retrieve the framework-generated AssistStructure that is stored within * the Bundle filled in by {@link Activity#onProvideAssistData}. */ diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index e0a30ad..3b026d2 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -19,6 +19,9 @@ package android.app; import android.animation.Animator; import android.animation.AnimatorInflater; import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.PropertyValuesHolder; +import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; @@ -403,6 +406,44 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate static final String VIEW_STATE_TAG = "android:view_state"; static final String USER_VISIBLE_HINT_TAG = "android:user_visible_hint"; + static class AnimateOnHWLayerIfNeededListener implements Animator.AnimatorListener { + private boolean mShouldRunOnHWLayer = false; + private View mView; + public AnimateOnHWLayerIfNeededListener(final View v) { + if (v == null) { + return; + } + mView = v; + } + + @Override + public void onAnimationStart(Animator animation) { + mShouldRunOnHWLayer = shouldRunOnHWLayer(mView, animation); + if (mShouldRunOnHWLayer) { + mView.setLayerType(View.LAYER_TYPE_HARDWARE, null); + } + } + + @Override + public void onAnimationEnd(Animator animation) { + if (mShouldRunOnHWLayer) { + mView.setLayerType(View.LAYER_TYPE_NONE, null); + } + mView = null; + animation.removeListener(this); + } + + @Override + public void onAnimationCancel(Animator animation) { + + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + } + ArrayList<Runnable> mPendingActions; Runnable[] mTmpActions; boolean mExecutingActions; @@ -467,6 +508,50 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate throw ex; } + static boolean modifiesAlpha(Animator anim) { + if (anim == null) { + return false; + } + if (anim instanceof ValueAnimator) { + ValueAnimator valueAnim = (ValueAnimator) anim; + PropertyValuesHolder[] values = valueAnim.getValues(); + for (int i = 0; i < values.length; i++) { + if (("alpha").equals(values[i].getPropertyName())) { + return true; + } + } + } else if (anim instanceof AnimatorSet) { + List<Animator> animList = ((AnimatorSet) anim).getChildAnimations(); + for (int i = 0; i < animList.size(); i++) { + if (modifiesAlpha(animList.get(i))) { + return true; + } + } + } + return false; + } + + static boolean shouldRunOnHWLayer(View v, Animator anim) { + if (v == null || anim == null) { + return false; + } + return v.getLayerType() == View.LAYER_TYPE_NONE + && v.hasOverlappingRendering() + && modifiesAlpha(anim); + } + + /** + * Sets the to be animated view on hardware layer during the animation. + */ + private void setHWLayerAnimListenerIfAlpha(final View v, Animator anim) { + if (v == null || anim == null) { + return; + } + if (shouldRunOnHWLayer(v, anim)) { + anim.addListener(new AnimateOnHWLayerIfNeededListener(v)); + } + } + @Override public FragmentTransaction beginTransaction() { return new BackStackRecord(this); @@ -894,6 +979,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate transitionStyle); if (anim != null) { anim.setTarget(f.mView); + setHWLayerAnimListenerIfAlpha(f.mView, anim); anim.start(); } container.addView(f.mView); @@ -975,6 +1061,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } }); anim.setTarget(f.mView); + setHWLayerAnimListenerIfAlpha(f.mView, anim); anim.start(); } @@ -1188,6 +1275,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } } }); + setHWLayerAnimListenerIfAlpha(finalFragment.mView, anim); anim.start(); } else { fragment.mView.setVisibility(View.GONE); @@ -1209,6 +1297,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate transitionStyle); if (anim != null) { anim.setTarget(fragment.mView); + setHWLayerAnimListenerIfAlpha(fragment.mView, anim); anim.start(); } fragment.mView.setVisibility(View.VISIBLE); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index c42719b..0a425ae 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -433,7 +433,8 @@ public interface IActivityManager extends IInterface { public void requestAssistContextExtras(int requestType, IResultReceiver receiver) throws RemoteException; - public void reportAssistContextExtras(IBinder token, Bundle extras) throws RemoteException; + public void reportAssistContextExtras(IBinder token, Bundle extras, + AssistStructure structure, AssistContent content) throws RemoteException; public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle) throws RemoteException; diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java index 022a62c..ba27c54 100644 --- a/core/java/android/app/VoiceInteractor.java +++ b/core/java/android/app/VoiceInteractor.java @@ -262,9 +262,9 @@ public class VoiceInteractor { /** * Create a new confirmation request. - * @param prompt Optional confirmation text to read to the user as the action being - * confirmed. - * @param extras Additional optional information. + * @param prompt Optional confirmation to speak to the user or null if nothing + * should be spoken. + * @param extras Additional optional information or null. */ public ConfirmationRequest(CharSequence prompt, Bundle extras) { mPrompt = prompt; @@ -305,7 +305,7 @@ public class VoiceInteractor { * Creates an option that a user can select with their voice by matching the label * or one of several synonyms. * @param label The label that will both be matched against what the user speaks - * and displayed visually. + * and displayed visually. */ public Option(CharSequence label) { mLabel = label; @@ -316,10 +316,10 @@ public class VoiceInteractor { * Creates an option that a user can select with their voice by matching the label * or one of several synonyms. * @param label The label that will both be matched against what the user speaks - * and displayed visually. + * and displayed visually. * @param index The location of this option within the overall set of options. - * Can be used to help identify the option when it is returned from the - * voice interactor. + * Can be used to help identify the option when it is returned from the + * voice interactor. */ public Option(CharSequence label, int index) { mLabel = label; @@ -330,7 +330,7 @@ public class VoiceInteractor { * Add a synonym term to the option to indicate an alternative way the content * may be matched. * @param synonym The synonym that will be matched against what the user speaks, - * but not displayed. + * but not displayed. */ public Option addSynonym(CharSequence synonym) { if (mSynonyms == null) { @@ -412,9 +412,10 @@ public class VoiceInteractor { /** * Create a new pick option request. - * @param prompt Optional question to be spoken to the user via text to speech. + * @param prompt Optional question to be asked of the user when the options are + * presented or null if nothing should be asked. * @param options The set of {@link Option}s the user is selecting from. - * @param extras Additional optional information. + * @param extras Additional optional information or null. */ public PickOptionRequest(CharSequence prompt, Option[] options, Bundle extras) { mPrompt = prompt; @@ -425,10 +426,10 @@ public class VoiceInteractor { /** * Called when a single option is confirmed or narrowed to one of several options. * @param finished True if the voice interaction has finished making a selection, in - * which case {@code selections} contains the final result. If false, this request is - * still active and you will continue to get calls on it. + * which case {@code selections} contains the final result. If false, this request is + * still active and you will continue to get calls on it. * @param selections Either a single {@link Option} or one of several {@link Option}s the - * user has narrowed the choices down to. + * user has narrowed the choices down to. * @param result Additional optional information. */ public void onPickOptionResult(boolean finished, Option[] selections, Bundle result) { @@ -455,8 +456,9 @@ public class VoiceInteractor { /** * Create a new completed voice interaction request. - * @param message Optional message to tell user about the completion status of the task. - * @param extras Additional optional information. + * @param message Optional message to speak to the user about the completion status of + * the task or null if nothing should be spoken. + * @param extras Additional optional information or null. */ public CompleteVoiceRequest(CharSequence message, Bundle extras) { mMessage = message; @@ -489,9 +491,9 @@ public class VoiceInteractor { /** * Create a new voice abort request. - * @param message Optional message to tell user about not being able to complete - * the interaction with voice. - * @param extras Additional optional information. + * @param message Optional message to speak to the user indicating why the task could + * not be completed by voice or null if nothing should be spoken. + * @param extras Additional optional information or null. */ public AbortVoiceRequest(CharSequence message, Bundle extras) { mMessage = message; @@ -508,7 +510,7 @@ public class VoiceInteractor { } /** - * Execute an extended command using the trusted system VoiceInteractionService. + * Execute a vendor-specific command using the trusted system VoiceInteractionService. * This allows an Activity to request additional information from the user needed to * complete an action (e.g. booking a table might have several possible times that the * user could select from or an app might need the user to agree to a terms of service). @@ -631,10 +633,11 @@ public class VoiceInteractor { /** * Queries the supported commands available from the VoiceinteractionService. * The command is a string that describes the generic operation to be performed. - * An example might be "com.google.voice.commands.REQUEST_NUMBER_BAGS" to request the number - * of bags as part of airline check-in. (This is not an actual working example.) + * An example might be "org.example.commands.PICK_DATE" to ask the user to pick + * a date. (Note: This is not an actual working example.) * - * @param commands + * @param commands The array of commands to query for support. + * @return Array of booleans indicating whether each command is supported or not. */ public boolean[] supportsCommands(String[] commands) { try { diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 52ccd7b..a0b95b6 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -16,6 +16,8 @@ package android.app.admin; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; @@ -76,7 +78,7 @@ import java.util.List; * <h3>Developer Guides</h3> * <p>For more information about managing policies for device administration, read the * <a href="{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a> - * developer guide.</p> + * developer guide. * </div> */ public class DevicePolicyManager { @@ -122,9 +124,6 @@ public class DevicePolicyManager { * * <p> If provisioning fails, the managedProfile is removed so the device returns to its * previous state. - * - * <p>Input: Nothing.</p> - * <p>Output: Nothing</p> */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_PROVISION_MANAGED_PROFILE @@ -155,7 +154,7 @@ public class DevicePolicyManager { * message containing an NFC record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}. * * <p> When this extra is set, the application must have exactly one device admin receiver. - * This receiver will be set as the profile or device owner and active admin.</p> + * This receiver will be set as the profile or device owner and active admin. * @see DeviceAdminReceiver * @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}. This extra is still @@ -212,7 +211,7 @@ public class DevicePolicyManager { /** * A Boolean extra that can be used by the mobile device management application to skip the - * disabling of system apps during provisioning when set to <code>true</code>. + * disabling of system apps during provisioning when set to {@code true}. * * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner * provisioning via an NFC bump. @@ -644,9 +643,6 @@ public class DevicePolicyManager { * * <p> * If provisioning fails, the device is factory reset. - * - * <p>Input: Nothing.</p> - * <p>Output: Nothing</p> */ public static final String MIME_TYPE_PROVISIONING_NFC_V2 = "application/com.android.managedprovisioning.v2"; @@ -847,18 +843,18 @@ public class DevicePolicyManager { * Return true if the given administrator component is currently * active (enabled) in the system. */ - public boolean isAdminActive(ComponentName who) { - return isAdminActiveAsUser(who, UserHandle.myUserId()); + public boolean isAdminActive(@NonNull ComponentName admin) { + return isAdminActiveAsUser(admin, UserHandle.myUserId()); } /** * @see #isAdminActive(ComponentName) * @hide */ - public boolean isAdminActiveAsUser(ComponentName who, int userId) { + public boolean isAdminActiveAsUser(@NonNull ComponentName admin, int userId) { if (mService != null) { try { - return mService.isAdminActive(who, userId); + return mService.isAdminActive(admin, userId); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -870,10 +866,10 @@ public class DevicePolicyManager { * for the user. * @hide */ - public boolean isRemovingAdmin(ComponentName who, int userId) { + public boolean isRemovingAdmin(@NonNull ComponentName admin, int userId) { if (mService != null) { try { - return mService.isRemovingAdmin(who, userId); + return mService.isRemovingAdmin(admin, userId); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -883,8 +879,8 @@ public class DevicePolicyManager { /** - * Return a list of all currently active device administrator's component - * names. Note that if there are no administrators than null may be + * Return a list of all currently active device administrators' component + * names. If there are no administrators {@code null} may be * returned. */ public List<ComponentName> getActiveAdmins() { @@ -928,10 +924,10 @@ public class DevicePolicyManager { * try to remove someone else's component, a security exception will be * thrown. */ - public void removeActiveAdmin(ComponentName who) { + public void removeActiveAdmin(@NonNull ComponentName admin) { if (mService != null) { try { - mService.removeActiveAdmin(who, UserHandle.myUserId()); + mService.removeActiveAdmin(admin, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -940,14 +936,14 @@ public class DevicePolicyManager { /** * Returns true if an administrator has been granted a particular device policy. This can - * be used to check if the administrator was activated under an earlier set of policies, + * be used to check whether the administrator was activated under an earlier set of policies, * but requires additional policies after an upgrade. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Must be * an active administrator, or an exception will be thrown. * @param usesPolicy Which uses-policy to check, as defined in {@link DeviceAdminInfo}. */ - public boolean hasGrantedPolicy(ComponentName admin, int usesPolicy) { + public boolean hasGrantedPolicy(@NonNull ComponentName admin, int usesPolicy) { if (mService != null) { try { return mService.hasGrantedPolicy(admin, usesPolicy, UserHandle.myUserId()); @@ -1048,7 +1044,7 @@ public class DevicePolicyManager { * {@link #PASSWORD_QUALITY_ALPHABETIC}, {@link #PASSWORD_QUALITY_ALPHANUMERIC} * or {@link #PASSWORD_QUALITY_COMPLEX}. */ - public void setPasswordQuality(ComponentName admin, int quality) { + public void setPasswordQuality(@NonNull ComponentName admin, int quality) { if (mService != null) { try { mService.setPasswordQuality(admin, quality); @@ -1061,15 +1057,15 @@ public class DevicePolicyManager { /** * Retrieve the current minimum password quality for all admins of this user * and its profiles or a particular one. - * @param admin The name of the admin component to check, or null to aggregate + * @param admin The name of the admin component to check, or {@code null} to aggregate * all admins. */ - public int getPasswordQuality(ComponentName admin) { + public int getPasswordQuality(@Nullable ComponentName admin) { return getPasswordQuality(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordQuality(ComponentName admin, int userHandle) { + public int getPasswordQuality(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordQuality(admin, userHandle); @@ -1101,7 +1097,7 @@ public class DevicePolicyManager { * @param length The new desired minimum password length. A value of 0 * means there is no restriction. */ - public void setPasswordMinimumLength(ComponentName admin, int length) { + public void setPasswordMinimumLength(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordMinimumLength(admin, length); @@ -1114,15 +1110,15 @@ public class DevicePolicyManager { /** * Retrieve the current minimum password length for all admins of this * user and its profiles or a particular one. - * @param admin The name of the admin component to check, or null to aggregate + * @param admin The name of the admin component to check, or {@code null} to aggregate * all admins. */ - public int getPasswordMinimumLength(ComponentName admin) { + public int getPasswordMinimumLength(@Nullable ComponentName admin) { return getPasswordMinimumLength(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordMinimumLength(ComponentName admin, int userHandle) { + public int getPasswordMinimumLength(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordMinimumLength(admin, userHandle); @@ -1155,7 +1151,7 @@ public class DevicePolicyManager { * required in the password. A value of 0 means there is no * restriction. */ - public void setPasswordMinimumUpperCase(ComponentName admin, int length) { + public void setPasswordMinimumUpperCase(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordMinimumUpperCase(admin, length); @@ -1173,17 +1169,17 @@ public class DevicePolicyManager { * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * - * @param admin The name of the admin component to check, or null to + * @param admin The name of the admin component to check, or {@code null} to * aggregate all admins. * @return The minimum number of upper case letters required in the * password. */ - public int getPasswordMinimumUpperCase(ComponentName admin) { + public int getPasswordMinimumUpperCase(@Nullable ComponentName admin) { return getPasswordMinimumUpperCase(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordMinimumUpperCase(ComponentName admin, int userHandle) { + public int getPasswordMinimumUpperCase(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordMinimumUpperCase(admin, userHandle); @@ -1216,7 +1212,7 @@ public class DevicePolicyManager { * required in the password. A value of 0 means there is no * restriction. */ - public void setPasswordMinimumLowerCase(ComponentName admin, int length) { + public void setPasswordMinimumLowerCase(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordMinimumLowerCase(admin, length); @@ -1234,17 +1230,17 @@ public class DevicePolicyManager { * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * - * @param admin The name of the admin component to check, or null to + * @param admin The name of the admin component to check, or {@code null} to * aggregate all admins. * @return The minimum number of lower case letters required in the * password. */ - public int getPasswordMinimumLowerCase(ComponentName admin) { + public int getPasswordMinimumLowerCase(@Nullable ComponentName admin) { return getPasswordMinimumLowerCase(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordMinimumLowerCase(ComponentName admin, int userHandle) { + public int getPasswordMinimumLowerCase(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordMinimumLowerCase(admin, userHandle); @@ -1276,7 +1272,7 @@ public class DevicePolicyManager { * @param length The new desired minimum number of letters required in the * password. A value of 0 means there is no restriction. */ - public void setPasswordMinimumLetters(ComponentName admin, int length) { + public void setPasswordMinimumLetters(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordMinimumLetters(admin, length); @@ -1293,16 +1289,16 @@ public class DevicePolicyManager { * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * - * @param admin The name of the admin component to check, or null to + * @param admin The name of the admin component to check, or {@code null} to * aggregate all admins. * @return The minimum number of letters required in the password. */ - public int getPasswordMinimumLetters(ComponentName admin) { + public int getPasswordMinimumLetters(@Nullable ComponentName admin) { return getPasswordMinimumLetters(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordMinimumLetters(ComponentName admin, int userHandle) { + public int getPasswordMinimumLetters(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordMinimumLetters(admin, userHandle); @@ -1334,7 +1330,7 @@ public class DevicePolicyManager { * @param length The new desired minimum number of numerical digits required * in the password. A value of 0 means there is no restriction. */ - public void setPasswordMinimumNumeric(ComponentName admin, int length) { + public void setPasswordMinimumNumeric(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordMinimumNumeric(admin, length); @@ -1352,16 +1348,16 @@ public class DevicePolicyManager { * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * - * @param admin The name of the admin component to check, or null to + * @param admin The name of the admin component to check, or {@code null} to * aggregate all admins. * @return The minimum number of numerical digits required in the password. */ - public int getPasswordMinimumNumeric(ComponentName admin) { + public int getPasswordMinimumNumeric(@Nullable ComponentName admin) { return getPasswordMinimumNumeric(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordMinimumNumeric(ComponentName admin, int userHandle) { + public int getPasswordMinimumNumeric(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordMinimumNumeric(admin, userHandle); @@ -1393,7 +1389,7 @@ public class DevicePolicyManager { * @param length The new desired minimum number of symbols required in the * password. A value of 0 means there is no restriction. */ - public void setPasswordMinimumSymbols(ComponentName admin, int length) { + public void setPasswordMinimumSymbols(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordMinimumSymbols(admin, length); @@ -1410,16 +1406,16 @@ public class DevicePolicyManager { * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * - * @param admin The name of the admin component to check, or null to + * @param admin The name of the admin component to check, or {@code null} to * aggregate all admins. * @return The minimum number of symbols required in the password. */ - public int getPasswordMinimumSymbols(ComponentName admin) { + public int getPasswordMinimumSymbols(@Nullable ComponentName admin) { return getPasswordMinimumSymbols(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordMinimumSymbols(ComponentName admin, int userHandle) { + public int getPasswordMinimumSymbols(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordMinimumSymbols(admin, userHandle); @@ -1451,7 +1447,7 @@ public class DevicePolicyManager { * @param length The new desired minimum number of letters required in the * password. A value of 0 means there is no restriction. */ - public void setPasswordMinimumNonLetter(ComponentName admin, int length) { + public void setPasswordMinimumNonLetter(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordMinimumNonLetter(admin, length); @@ -1469,16 +1465,16 @@ public class DevicePolicyManager { * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * - * @param admin The name of the admin component to check, or null to + * @param admin The name of the admin component to check, or {@code null} to * aggregate all admins. * @return The minimum number of letters required in the password. */ - public int getPasswordMinimumNonLetter(ComponentName admin) { + public int getPasswordMinimumNonLetter(@Nullable ComponentName admin) { return getPasswordMinimumNonLetter(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordMinimumNonLetter(ComponentName admin, int userHandle) { + public int getPasswordMinimumNonLetter(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordMinimumNonLetter(admin, userHandle); @@ -1511,7 +1507,7 @@ public class DevicePolicyManager { * @param length The new desired length of password history. A value of 0 * means there is no restriction. */ - public void setPasswordHistoryLength(ComponentName admin, int length) { + public void setPasswordHistoryLength(@NonNull ComponentName admin, int length) { if (mService != null) { try { mService.setPasswordHistoryLength(admin, length); @@ -1543,7 +1539,7 @@ public class DevicePolicyManager { * @param timeout The limit (in ms) that a password can remain in effect. A value of 0 * means there is no restriction (unlimited). */ - public void setPasswordExpirationTimeout(ComponentName admin, long timeout) { + public void setPasswordExpirationTimeout(@NonNull ComponentName admin, long timeout) { if (mService != null) { try { mService.setPasswordExpirationTimeout(admin, timeout); @@ -1557,12 +1553,12 @@ public class DevicePolicyManager { * Get the password expiration timeout for the given admin. The expiration timeout is the * recurring expiration timeout provided in the call to * {@link #setPasswordExpirationTimeout(ComponentName, long)} for the given admin or the - * aggregate of all policy administrators if admin is null. + * aggregate of all policy administrators if {@code admin} is null. * - * @param admin The name of the admin component to check, or null to aggregate all admins. + * @param admin The name of the admin component to check, or {@code null} to aggregate all admins. * @return The timeout for the given admin or the minimum of all timeouts */ - public long getPasswordExpirationTimeout(ComponentName admin) { + public long getPasswordExpirationTimeout(@Nullable ComponentName admin) { if (mService != null) { try { return mService.getPasswordExpirationTimeout(admin, UserHandle.myUserId()); @@ -1580,10 +1576,10 @@ public class DevicePolicyManager { * If admin is null, then a composite of all expiration timeouts is returned * - which will be the minimum of all timeouts. * - * @param admin The name of the admin component to check, or null to aggregate all admins. + * @param admin The name of the admin component to check, or {@code null} to aggregate all admins. * @return The password expiration time, in ms. */ - public long getPasswordExpiration(ComponentName admin) { + public long getPasswordExpiration(@Nullable ComponentName admin) { if (mService != null) { try { return mService.getPasswordExpiration(admin, UserHandle.myUserId()); @@ -1597,16 +1593,16 @@ public class DevicePolicyManager { /** * Retrieve the current password history length for all admins of this * user and its profiles or a particular one. - * @param admin The name of the admin component to check, or null to aggregate + * @param admin The name of the admin component to check, or {@code null} to aggregate * all admins. * @return The length of the password history */ - public int getPasswordHistoryLength(ComponentName admin) { + public int getPasswordHistoryLength(@Nullable ComponentName admin) { return getPasswordHistoryLength(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getPasswordHistoryLength(ComponentName admin, int userHandle) { + public int getPasswordHistoryLength(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getPasswordHistoryLength(admin, userHandle); @@ -1705,7 +1701,7 @@ public class DevicePolicyManager { * @param num The number of failed password attempts at which point the * device will wipe its data. */ - public void setMaximumFailedPasswordsForWipe(ComponentName admin, int num) { + public void setMaximumFailedPasswordsForWipe(@NonNull ComponentName admin, int num) { if (mService != null) { try { mService.setMaximumFailedPasswordsForWipe(admin, num); @@ -1719,15 +1715,15 @@ public class DevicePolicyManager { * Retrieve the current maximum number of login attempts that are allowed * before the device wipes itself, for all admins of this user and its profiles * or a particular one. - * @param admin The name of the admin component to check, or null to aggregate + * @param admin The name of the admin component to check, or {@code null} to aggregate * all admins. */ - public int getMaximumFailedPasswordsForWipe(ComponentName admin) { + public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin) { return getMaximumFailedPasswordsForWipe(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getMaximumFailedPasswordsForWipe(ComponentName admin, int userHandle) { + public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getMaximumFailedPasswordsForWipe(admin, userHandle); @@ -1824,7 +1820,7 @@ public class DevicePolicyManager { * @param timeMs The new desired maximum time to lock in milliseconds. * A value of 0 means there is no restriction. */ - public void setMaximumTimeToLock(ComponentName admin, long timeMs) { + public void setMaximumTimeToLock(@NonNull ComponentName admin, long timeMs) { if (mService != null) { try { mService.setMaximumTimeToLock(admin, timeMs); @@ -1837,17 +1833,17 @@ public class DevicePolicyManager { /** * Retrieve the current maximum time to unlock for all admins of this user * and its profiles or a particular one. - * @param admin The name of the admin component to check, or null to aggregate + * @param admin The name of the admin component to check, or {@code null} to aggregate * all admins. * @return time in milliseconds for the given admin or the minimum value (strictest) of * all admins if admin is null. Returns 0 if there are no restrictions. */ - public long getMaximumTimeToLock(ComponentName admin) { + public long getMaximumTimeToLock(@Nullable ComponentName admin) { return getMaximumTimeToLock(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public long getMaximumTimeToLock(ComponentName admin, int userHandle) { + public long getMaximumTimeToLock(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getMaximumTimeToLock(admin, userHandle); @@ -1922,21 +1918,20 @@ public class DevicePolicyManager { * this method; if it has not, a security exception will be thrown. * Only the first device admin can set the proxy. If a second admin attempts * to set the proxy, the {@link ComponentName} of the admin originally setting the - * proxy will be returned. If successful in setting the proxy, null will + * proxy will be returned. If successful in setting the proxy, {@code null} will * be returned. * The method can be called repeatedly by the device admin alrady setting the * proxy to update the proxy and exclusion list. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated - * with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param proxySpec the global proxy desired. Must be an HTTP Proxy. * Pass Proxy.NO_PROXY to reset the proxy. * @param exclusionList a list of domains to be excluded from the global proxy. - * @return returns null if the proxy was successfully set, or a {@link ComponentName} - * of the device admin that sets thew proxy otherwise. + * @return {@code null} if the proxy was successfully set, or otherwise a {@link ComponentName} + * of the device admin that sets the proxy. * @hide */ - public ComponentName setGlobalProxy(ComponentName admin, Proxy proxySpec, + public ComponentName setGlobalProxy(@NonNull ComponentName admin, Proxy proxySpec, List<String> exclusionList ) { if (proxySpec == null) { throw new NullPointerException(); @@ -2001,7 +1996,8 @@ public class DevicePolicyManager { * @param proxyInfo The a {@link ProxyInfo} object defining the new global * HTTP proxy. A {@code null} value will clear the global HTTP proxy. */ - public void setRecommendedGlobalProxy(ComponentName admin, ProxyInfo proxyInfo) { + public void setRecommendedGlobalProxy(@NonNull ComponentName admin, @Nullable ProxyInfo + proxyInfo) { if (mService != null) { try { mService.setRecommendedGlobalProxy(admin, proxyInfo); @@ -2013,8 +2009,8 @@ public class DevicePolicyManager { /** * Returns the component name setting the global proxy. - * @return ComponentName object of the device admin that set the global proxy, or - * null if no admin has set the proxy. + * @return ComponentName object of the device admin that set the global proxy, or {@code null} + * if no admin has set the proxy. * @hide */ public ComponentName getGlobalProxyAdmin() { @@ -2147,7 +2143,7 @@ public class DevicePolicyManager { * {@link #ENCRYPTION_STATUS_ACTIVE}. This is the value of the requests; Use * {@link #getStorageEncryptionStatus()} to query the actual device state. */ - public int setStorageEncryption(ComponentName admin, boolean encrypt) { + public int setStorageEncryption(@NonNull ComponentName admin, boolean encrypt) { if (mService != null) { try { return mService.setStorageEncryption(admin, encrypt); @@ -2167,7 +2163,7 @@ public class DevicePolicyManager { * administrators. * @return true if the admin(s) are requesting encryption, false if not. */ - public boolean getStorageEncryption(ComponentName admin) { + public boolean getStorageEncryption(@Nullable ComponentName admin) { if (mService != null) { try { return mService.getStorageEncryption(admin, UserHandle.myUserId()); @@ -2216,14 +2212,14 @@ public class DevicePolicyManager { /** * Installs the given certificate as a user CA. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use - * <code>null</code> if calling from a delegated certificate installer. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. * @param certBuffer encoded form of the certificate to install. * * @return false if the certBuffer cannot be parsed or installation is * interrupted, true otherwise. */ - public boolean installCaCert(ComponentName admin, byte[] certBuffer) { + public boolean installCaCert(@Nullable ComponentName admin, byte[] certBuffer) { if (mService != null) { try { return mService.installCaCert(admin, certBuffer); @@ -2237,11 +2233,11 @@ public class DevicePolicyManager { /** * Uninstalls the given certificate from trusted user CAs, if present. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use - * <code>null</code> if calling from a delegated certificate installer. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. * @param certBuffer encoded form of the certificate to remove. */ - public void uninstallCaCert(ComponentName admin, byte[] certBuffer) { + public void uninstallCaCert(@Nullable ComponentName admin, byte[] certBuffer) { if (mService != null) { try { final String alias = getCaCertAlias(certBuffer); @@ -2259,11 +2255,11 @@ public class DevicePolicyManager { * If a user has installed any certificates by other means than device policy these will be * included too. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use - * <code>null</code> if calling from a delegated certificate installer. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. * @return a List of byte[] arrays, each encoding one user CA certificate. */ - public List<byte[]> getInstalledCaCerts(ComponentName admin) { + public List<byte[]> getInstalledCaCerts(@Nullable ComponentName admin) { List<byte[]> certs = new ArrayList<byte[]>(); if (mService != null) { try { @@ -2287,10 +2283,10 @@ public class DevicePolicyManager { * Uninstalls all custom trusted CA certificates from the profile. Certificates installed by * means other than device policy will also be removed, except for system CA certificates. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use - * <code>null</code> if calling from a delegated certificate installer. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. */ - public void uninstallAllUserCaCerts(ComponentName admin) { + public void uninstallAllUserCaCerts(@Nullable ComponentName admin) { if (mService != null) { for (String alias : new TrustedCertificateStore().userAliases()) { try { @@ -2305,11 +2301,11 @@ public class DevicePolicyManager { /** * Returns whether this certificate is installed as a trusted CA. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use - * <code>null</code> if calling from a delegated certificate installer. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. * @param certBuffer encoded form of the certificate to look up. */ - public boolean hasCaCertInstalled(ComponentName admin, byte[] certBuffer) { + public boolean hasCaCertInstalled(@Nullable ComponentName admin, byte[] certBuffer) { if (mService != null) { try { mService.enforceCanManageCaCerts(admin); @@ -2327,21 +2323,21 @@ public class DevicePolicyManager { * Called by a device or profile owner to install a certificate and private key pair. The * keypair will be visible to all apps within the profile. * - * @param who Which {@link DeviceAdminReceiver} this request is associated with. Use - * <code>null</code> if calling from a delegated certificate installer. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. * @param privKey The private key to install. * @param cert The certificate to install. * @param alias The private key alias under which to install the certificate. If a certificate * with that alias already exists, it will be overwritten. * @return {@code true} if the keys were installed, {@code false} otherwise. */ - public boolean installKeyPair(ComponentName who, PrivateKey privKey, Certificate cert, + public boolean installKeyPair(@Nullable ComponentName admin, PrivateKey privKey, Certificate cert, String alias) { try { final byte[] pemCert = Credentials.convertToPem(cert); final byte[] pkcs8Key = KeyFactory.getInstance(privKey.getAlgorithm()) .getKeySpec(privKey, PKCS8EncodedKeySpec.class).getEncoded(); - return mService.installKeyPair(who, pkcs8Key, pemCert, alias); + return mService.installKeyPair(admin, pkcs8Key, pemCert, alias); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { @@ -2353,7 +2349,7 @@ public class DevicePolicyManager { } /** - * Returns the alias of a given CA certificate in the certificate store, or null if it + * @return the alias of a given CA certificate in the certificate store, or {@code null} if it * doesn't exist. */ private static String getCaCertAlias(byte[] certBuffer) throws CertificateException { @@ -2373,15 +2369,15 @@ public class DevicePolicyManager { * it is later cleared by calling this method with a null value or uninstallling the certificate * installer. * - * @param who Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param installerPackage The package name of the certificate installer which will be given - * access. If <code>null</code> is given the current package will be cleared. + * access. If {@code null} is given the current package will be cleared. */ - public void setCertInstallerPackage(ComponentName who, String installerPackage) - throws SecurityException { + public void setCertInstallerPackage(@NonNull ComponentName admin, @Nullable String + installerPackage) throws SecurityException { if (mService != null) { try { - mService.setCertInstallerPackage(who, installerPackage); + mService.setCertInstallerPackage(admin, installerPackage); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -2392,14 +2388,14 @@ public class DevicePolicyManager { * Called by a profile owner or device owner to retrieve the certificate installer for the * current user. null if none is set. * - * @param who Which {@link DeviceAdminReceiver} this request is associated with. - * @return The package name of the current delegated certificate installer. <code>null</code> + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @return The package name of the current delegated certificate installer, or {@code null} * if none is set. */ - public String getCertInstallerPackage(ComponentName who) throws SecurityException { + public String getCertInstallerPackage(@NonNull ComponentName admin) throws SecurityException { if (mService != null) { try { - return mService.getCertInstallerPackage(who); + return mService.getCertInstallerPackage(admin); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -2419,7 +2415,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param disabled Whether or not the camera should be disabled. */ - public void setCameraDisabled(ComponentName admin, boolean disabled) { + public void setCameraDisabled(@NonNull ComponentName admin, boolean disabled) { if (mService != null) { try { mService.setCameraDisabled(admin, disabled); @@ -2432,15 +2428,15 @@ public class DevicePolicyManager { /** * Determine whether or not the device's cameras have been disabled for this user, * either by the current admin, if specified, or all admins. - * @param admin The name of the admin component to check, or null to check if any admins + * @param admin The name of the admin component to check, or {@code null} to check whether any admins * have disabled the camera */ - public boolean getCameraDisabled(ComponentName admin) { + public boolean getCameraDisabled(@Nullable ComponentName admin) { return getCameraDisabled(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public boolean getCameraDisabled(ComponentName admin, int userHandle) { + public boolean getCameraDisabled(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getCameraDisabled(admin, userHandle); @@ -2463,7 +2459,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param disabled Whether screen capture is disabled or not. */ - public void setScreenCaptureDisabled(ComponentName admin, boolean disabled) { + public void setScreenCaptureDisabled(@NonNull ComponentName admin, boolean disabled) { if (mService != null) { try { mService.setScreenCaptureDisabled(admin, disabled); @@ -2476,15 +2472,15 @@ public class DevicePolicyManager { /** * Determine whether or not screen capture has been disabled by the current * admin, if specified, or all admins. - * @param admin The name of the admin component to check, or null to check if any admins + * @param admin The name of the admin component to check, or {@code null} to check whether any admins * have disabled screen capture. */ - public boolean getScreenCaptureDisabled(ComponentName admin) { + public boolean getScreenCaptureDisabled(@Nullable ComponentName admin) { return getScreenCaptureDisabled(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public boolean getScreenCaptureDisabled(ComponentName admin, int userHandle) { + public boolean getScreenCaptureDisabled(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getScreenCaptureDisabled(admin, userHandle); @@ -2507,7 +2503,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param required Whether auto time is set required or not. */ - public void setAutoTimeRequired(ComponentName admin, boolean required) { + public void setAutoTimeRequired(@NonNull ComponentName admin, boolean required) { if (mService != null) { try { mService.setAutoTimeRequired(admin, required); @@ -2561,7 +2557,7 @@ public class DevicePolicyManager { * {@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS}, {@link #KEYGUARD_DISABLE_FINGERPRINT}, * {@link #KEYGUARD_DISABLE_FEATURES_ALL} */ - public void setKeyguardDisabledFeatures(ComponentName admin, int which) { + public void setKeyguardDisabledFeatures(@NonNull ComponentName admin, int which) { if (mService != null) { try { mService.setKeyguardDisabledFeatures(admin, which); @@ -2574,17 +2570,17 @@ public class DevicePolicyManager { /** * Determine whether or not features have been disabled in keyguard either by the current * admin, if specified, or all admins. - * @param admin The name of the admin component to check, or null to check if any admins + * @param admin The name of the admin component to check, or {@code null} to check whether any admins * have disabled features in keyguard. * @return bitfield of flags. See {@link #setKeyguardDisabledFeatures(ComponentName, int)} * for a list. */ - public int getKeyguardDisabledFeatures(ComponentName admin) { + public int getKeyguardDisabledFeatures(@Nullable ComponentName admin) { return getKeyguardDisabledFeatures(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getKeyguardDisabledFeatures(ComponentName admin, int userHandle) { + public int getKeyguardDisabledFeatures(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { return mService.getKeyguardDisabledFeatures(admin, userHandle); @@ -2598,7 +2594,8 @@ public class DevicePolicyManager { /** * @hide */ - public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing, int userHandle) { + public void setActiveAdmin(@NonNull ComponentName policyReceiver, boolean refreshing, + int userHandle) { if (mService != null) { try { mService.setActiveAdmin(policyReceiver, refreshing, userHandle); @@ -2611,15 +2608,15 @@ public class DevicePolicyManager { /** * @hide */ - public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing) { + public void setActiveAdmin(@NonNull ComponentName policyReceiver, boolean refreshing) { setActiveAdmin(policyReceiver, refreshing, UserHandle.myUserId()); } /** - * Returns the DeviceAdminInfo as defined by the administrator's package info & meta-data + * Returns the DeviceAdminInfo as defined by the administrator's package info & meta-data * @hide */ - public DeviceAdminInfo getAdminInfo(ComponentName cn) { + public DeviceAdminInfo getAdminInfo(@NonNull ComponentName cn) { ActivityInfo ai; try { ai = mContext.getPackageManager().getReceiverInfo(cn, @@ -2646,7 +2643,7 @@ public class DevicePolicyManager { /** * @hide */ - public void getRemoveWarning(ComponentName admin, RemoteCallback result) { + public void getRemoveWarning(@Nullable ComponentName admin, RemoteCallback result) { if (mService != null) { try { mService.getRemoveWarning(admin, result, UserHandle.myUserId()); @@ -2740,10 +2737,10 @@ public class DevicePolicyManager { /** * Used to determine if a particular package has been registered as a Device Owner app. * A device owner app is a special device admin that cannot be deactivated by the user, once - * activated as a device admin. It also cannot be uninstalled. To check if a particular + * activated as a device admin. It also cannot be uninstalled. To check whether a particular * package is currently registered as the device owner app, pass in the package name from * {@link Context#getPackageName()} to this method.<p/>This is useful for device - * admin apps that want to check if they are also registered as the device owner app. The + * admin apps that want to check whether they are also registered as the device owner app. The * exact mechanism by which a device admin app is registered as a device owner app is defined by * the setup process. * @param packageName the package name of the app, to compare with the registered device owner @@ -2820,19 +2817,20 @@ public class DevicePolicyManager { * MANAGE_DEVICE_ADMINS permission before the device is provisioned or by a device owner app. A * device initializer app is granted device owner privileges during device initialization and * profile owner privileges during secondary user initialization. - * @param who Which {@link DeviceAdminReceiver} this request is associated with, or null if not - * called by the device owner. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if not called by the device owner. * @param initializer Which {@link DeviceAdminReceiver} to make device initializer. * @return whether the component was successfully registered as the device initializer. * @throws IllegalArgumentException if the componentname is null or invalid * @throws IllegalStateException if the caller is not device owner or the device has * already been provisioned or a device initializer already exists. */ - public boolean setDeviceInitializer(ComponentName who, ComponentName initializer) + public boolean setDeviceInitializer(@Nullable ComponentName admin, + @NonNull ComponentName initializer) throws IllegalArgumentException, IllegalStateException { if (mService != null) { try { - return mService.setDeviceInitializer(who, initializer); + return mService.setDeviceInitializer(admin, initializer); } catch (RemoteException re) { Log.w(TAG, "Failed to set device initializer"); } @@ -2863,12 +2861,12 @@ public class DevicePolicyManager { * subsequently created users. This method can be called by either the device owner or device * initializer itself. The caller must be an active administrator. * - * @param who Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. */ - public void clearDeviceInitializerApp(ComponentName who) { + public void clearDeviceInitializerApp(@NonNull ComponentName admin) { if (mService != null) { try { - mService.clearDeviceInitializer(who); + mService.clearDeviceInitializer(admin); } catch (RemoteException re) { Log.w(TAG, "Failed to clear device initializer"); } @@ -2927,7 +2925,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @return whether the user is now enabled. */ - public boolean setUserEnabled(ComponentName admin) { + public boolean setUserEnabled(@NonNull ComponentName admin) { if (mService != null) { try { return mService.setUserEnabled(admin); @@ -2955,7 +2953,7 @@ public class DevicePolicyManager { * the user has already been set up. */ @SystemApi - public boolean setActiveProfileOwner(ComponentName admin, @Deprecated String ownerName) + public boolean setActiveProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName) throws IllegalArgumentException { if (mService != null) { try { @@ -2980,7 +2978,7 @@ public class DevicePolicyManager { * @return */ @SystemApi - public void clearProfileOwner(ComponentName admin) { + public void clearProfileOwner(@NonNull ComponentName admin) { if (mService != null) { try { mService.clearProfileOwner(admin); @@ -2992,14 +2990,14 @@ public class DevicePolicyManager { /** * @hide - * Checks if the user was already setup. + * Checks whether the user was already setup. */ public boolean hasUserSetupCompleted() { if (mService != null) { try { return mService.hasUserSetupCompleted(); } catch (RemoteException re) { - Log.w(TAG, "Failed to check if user setup has completed"); + Log.w(TAG, "Failed to check whether user setup has completed"); } } return true; @@ -3021,7 +3019,7 @@ public class DevicePolicyManager { * @throws IllegalArgumentException if admin is null, the package isn't installed, or the * preconditions mentioned are not met. */ - public boolean setProfileOwner(ComponentName admin, @Deprecated String ownerName, + public boolean setProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName, int userHandle) throws IllegalArgumentException { if (admin == null) { throw new NullPointerException("admin cannot be null"); @@ -3048,7 +3046,7 @@ public class DevicePolicyManager { * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. */ - public void setProfileEnabled(ComponentName admin) { + public void setProfileEnabled(@NonNull ComponentName admin) { if (mService != null) { try { mService.setProfileEnabled(admin); @@ -3066,17 +3064,18 @@ public class DevicePolicyManager { * @see #isProfileOwnerApp * @see #isDeviceOwnerApp * + * @param admin Which {@link DeviceAdminReceiver} this request is associate with. * @param profileName The name of the profile. */ - public void setProfileName(ComponentName who, String profileName) { + public void setProfileName(@NonNull ComponentName admin, String profileName) { if (mService != null) { try { - mService.setProfileName(who, profileName); - } catch (RemoteException e) { - Log.w(TAG, "Failed talking with device policy service", e); + mService.setProfileName(admin, profileName); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } } } -} /** * Used to determine if a particular package is registered as the profile owner for the @@ -3102,7 +3101,7 @@ public class DevicePolicyManager { /** * @hide - * @return the packageName of the owner of the given user profile or null if no profile + * @return the packageName of the owner of the given user profile or {@code null} if no profile * owner has been set for that user. * @throws IllegalArgumentException if the userId is invalid. */ @@ -3130,8 +3129,8 @@ public class DevicePolicyManager { /** * @hide - * @return the human readable name of the organisation associated with this DPM or null if - * one is not set. + * @return the human readable name of the organisation associated with this DPM or {@code null} + * if one is not set. * @throws IllegalArgumentException if the userId is invalid. */ public String getProfileOwnerName() throws IllegalArgumentException { @@ -3185,8 +3184,8 @@ public class DevicePolicyManager { * @param filter The IntentFilter for which a default handler is added. * @param activity The Activity that is added as default intent handler. */ - public void addPersistentPreferredActivity(ComponentName admin, IntentFilter filter, - ComponentName activity) { + public void addPersistentPreferredActivity(@NonNull ComponentName admin, IntentFilter filter, + @NonNull ComponentName activity) { if (mService != null) { try { mService.addPersistentPreferredActivity(admin, filter, activity); @@ -3206,7 +3205,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param packageName The name of the package for which preferences are removed. */ - public void clearPackagePersistentPreferredActivities(ComponentName admin, + public void clearPackagePersistentPreferredActivities(@NonNull ComponentName admin, String packageName) { if (mService != null) { try { @@ -3241,7 +3240,7 @@ public class DevicePolicyManager { * * @see UserManager#KEY_RESTRICTIONS_PENDING */ - public void setApplicationRestrictions(ComponentName admin, String packageName, + public void setApplicationRestrictions(@NonNull ComponentName admin, String packageName, Bundle settings) { if (mService != null) { try { @@ -3271,8 +3270,8 @@ public class DevicePolicyManager { * then it's up to the TrustAgent itself to aggregate the values from all device admins. * <p>Consult documentation for the specific TrustAgent to determine legal options parameters. */ - public void setTrustAgentConfiguration(ComponentName admin, ComponentName target, - PersistableBundle configuration) { + public void setTrustAgentConfiguration(@NonNull ComponentName admin, + @NonNull ComponentName target, PersistableBundle configuration) { if (mService != null) { try { mService.setTrustAgentConfiguration(admin, target, configuration); @@ -3296,14 +3295,14 @@ public class DevicePolicyManager { * @param agent Which component to get enabled features for. * @return configuration for the given trust agent. */ - public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin, - ComponentName agent) { + public List<PersistableBundle> getTrustAgentConfiguration(@Nullable ComponentName admin, + @NonNull ComponentName agent) { return getTrustAgentConfiguration(admin, agent, UserHandle.myUserId()); } /** @hide per-user version */ - public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin, - ComponentName agent, int userHandle) { + public List<PersistableBundle> getTrustAgentConfiguration(@Nullable ComponentName admin, + @NonNull ComponentName agent, int userHandle) { if (mService != null) { try { return mService.getTrustAgentConfiguration(admin, agent, userHandle); @@ -3321,13 +3320,13 @@ public class DevicePolicyManager { * <p>The calling device admin must be a profile owner. If it is not, a * security exception will be thrown. * - * @param who Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param disabled If true caller-Id information in the managed profile is not displayed. */ - public void setCrossProfileCallerIdDisabled(ComponentName who, boolean disabled) { + public void setCrossProfileCallerIdDisabled(@NonNull ComponentName admin, boolean disabled) { if (mService != null) { try { - mService.setCrossProfileCallerIdDisabled(who, disabled); + mService.setCrossProfileCallerIdDisabled(admin, disabled); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -3341,12 +3340,12 @@ public class DevicePolicyManager { * <p>The calling device admin must be a profile owner. If it is not, a * security exception will be thrown. * - * @param who Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. */ - public boolean getCrossProfileCallerIdDisabled(ComponentName who) { + public boolean getCrossProfileCallerIdDisabled(@NonNull ComponentName admin) { if (mService != null) { try { - return mService.getCrossProfileCallerIdDisabled(who); + return mService.getCrossProfileCallerIdDisabled(admin); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -3396,15 +3395,15 @@ public class DevicePolicyManager { * <p> * This API works on managed profile only. * - * @param who Which {@link DeviceAdminReceiver} this request is associated + * @param admin Which {@link DeviceAdminReceiver} this request is associated * with. * @param disabled If true, bluetooth devices cannot access enterprise * contacts. */ - public void setBluetoothContactSharingDisabled(ComponentName who, boolean disabled) { + public void setBluetoothContactSharingDisabled(@NonNull ComponentName admin, boolean disabled) { if (mService != null) { try { - mService.setBluetoothContactSharingDisabled(who, disabled); + mService.setBluetoothContactSharingDisabled(admin, disabled); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -3420,13 +3419,13 @@ public class DevicePolicyManager { * <p> * This API works on managed profile only. * - * @param who Which {@link DeviceAdminReceiver} this request is associated + * @param admin Which {@link DeviceAdminReceiver} this request is associated * with. */ - public boolean getBluetoothContactSharingDisabled(ComponentName who) { + public boolean getBluetoothContactSharingDisabled(@NonNull ComponentName admin) { if (mService != null) { try { - return mService.getBluetoothContactSharingDisabled(who); + return mService.getBluetoothContactSharingDisabled(admin); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -3465,7 +3464,7 @@ public class DevicePolicyManager { * @param flags {@link DevicePolicyManager#FLAG_MANAGED_CAN_ACCESS_PARENT} and * {@link DevicePolicyManager#FLAG_PARENT_CAN_ACCESS_MANAGED} are supported. */ - public void addCrossProfileIntentFilter(ComponentName admin, IntentFilter filter, int flags) { + public void addCrossProfileIntentFilter(@NonNull ComponentName admin, IntentFilter filter, int flags) { if (mService != null) { try { mService.addCrossProfileIntentFilter(admin, filter, flags); @@ -3481,7 +3480,7 @@ public class DevicePolicyManager { * Only removes those that have been set by the profile owner. * @param admin Which {@link DeviceAdminReceiver} this request is associated with. */ - public void clearCrossProfileIntentFilters(ComponentName admin) { + public void clearCrossProfileIntentFilters(@NonNull ComponentName admin) { if (mService != null) { try { mService.clearCrossProfileIntentFilters(admin); @@ -3512,7 +3511,7 @@ public class DevicePolicyManager { * @return true if setting the restriction succeeded. It fail if there is * one or more non-system accessibility services enabled, that are not in the list. */ - public boolean setPermittedAccessibilityServices(ComponentName admin, + public boolean setPermittedAccessibilityServices(@NonNull ComponentName admin, List<String> packageNames) { if (mService != null) { try { @@ -3533,7 +3532,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @return List of accessiblity service package names. */ - public List<String> getPermittedAccessibilityServices(ComponentName admin) { + public List<String> getPermittedAccessibilityServices(@NonNull ComponentName admin) { if (mService != null) { try { return mService.getPermittedAccessibilityServices(admin); @@ -3591,7 +3590,7 @@ public class DevicePolicyManager { * one or more non-system input methods currently enabled that are not in * the packageNames list. */ - public boolean setPermittedInputMethods(ComponentName admin, List<String> packageNames) { + public boolean setPermittedInputMethods(@NonNull ComponentName admin, List<String> packageNames) { if (mService != null) { try { return mService.setPermittedInputMethods(admin, packageNames); @@ -3612,7 +3611,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @return List of input method package names. */ - public List<String> getPermittedInputMethods(ComponentName admin) { + public List<String> getPermittedInputMethods(@NonNull ComponentName admin) { if (mService != null) { try { return mService.getPermittedInputMethods(admin); @@ -3655,9 +3654,10 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param name the user's name * @see UserHandle - * @return the UserHandle object for the created user, or null if the user could not be created. + * @return the {@link android.os.UserHandle} object for the created user, or {@code null} if the + * user could not be created. */ - public UserHandle createUser(ComponentName admin, String name) { + public UserHandle createUser(@NonNull ComponentName admin, String name) { try { return mService.createUser(admin, name); } catch (RemoteException re) { @@ -3688,10 +3688,11 @@ public class DevicePolicyManager { * @param adminExtras Extras that will be passed to onEnable of the admin receiver * on the new user. * @see UserHandle - * @return the UserHandle object for the created user, or null if the user could not be created. + * @return the {@link android.os.UserHandle} object for the created user, or {@code null} if the + * user could not be created. */ - public UserHandle createAndInitializeUser(ComponentName admin, String name, String ownerName, - ComponentName profileOwnerComponent, Bundle adminExtras) { + public UserHandle createAndInitializeUser(@NonNull ComponentName admin, String name, + String ownerName, @NonNull ComponentName profileOwnerComponent, Bundle adminExtras) { try { return mService.createAndInitializeUser(admin, name, ownerName, profileOwnerComponent, adminExtras); @@ -3709,7 +3710,7 @@ public class DevicePolicyManager { * @param userHandle the user to remove. * @return {@code true} if the user was removed, {@code false} otherwise. */ - public boolean removeUser(ComponentName admin, UserHandle userHandle) { + public boolean removeUser(@NonNull ComponentName admin, UserHandle userHandle) { try { return mService.removeUser(admin, userHandle); } catch (RemoteException re) { @@ -3727,7 +3728,7 @@ public class DevicePolicyManager { * * @see Intent#ACTION_USER_FOREGROUND */ - public boolean switchUser(ComponentName admin, UserHandle userHandle) { + public boolean switchUser(@NonNull ComponentName admin, @Nullable UserHandle userHandle) { try { return mService.switchUser(admin, userHandle); } catch (RemoteException re) { @@ -3749,7 +3750,7 @@ public class DevicePolicyManager { * {@link DevicePolicyManager#setApplicationRestrictions} was called, or an empty {@link Bundle} * if no restrictions have been set. */ - public Bundle getApplicationRestrictions(ComponentName admin, String packageName) { + public Bundle getApplicationRestrictions(@NonNull ComponentName admin, String packageName) { if (mService != null) { try { return mService.getApplicationRestrictions(admin, packageName); @@ -3771,7 +3772,7 @@ public class DevicePolicyManager { * @param key The key of the restriction. See the constants in * {@link android.os.UserManager} for the list of keys. */ - public void addUserRestriction(ComponentName admin, String key) { + public void addUserRestriction(@NonNull ComponentName admin, String key) { if (mService != null) { try { mService.setUserRestriction(admin, key, true); @@ -3792,7 +3793,7 @@ public class DevicePolicyManager { * @param key The key of the restriction. See the constants in * {@link android.os.UserManager} for the list of keys. */ - public void clearUserRestriction(ComponentName admin, String key) { + public void clearUserRestriction(@NonNull ComponentName admin, String key) { if (mService != null) { try { mService.setUserRestriction(admin, key, false); @@ -3812,7 +3813,7 @@ public class DevicePolicyManager { * unhidden. * @return boolean Whether the hidden setting of the package was successfully updated. */ - public boolean setApplicationHidden(ComponentName admin, String packageName, + public boolean setApplicationHidden(@NonNull ComponentName admin, String packageName, boolean hidden) { if (mService != null) { try { @@ -3831,7 +3832,7 @@ public class DevicePolicyManager { * @param packageName The name of the package to retrieve the hidden status of. * @return boolean {@code true} if the package is hidden, {@code false} otherwise. */ - public boolean isApplicationHidden(ComponentName admin, String packageName) { + public boolean isApplicationHidden(@NonNull ComponentName admin, String packageName) { if (mService != null) { try { return mService.isApplicationHidden(admin, packageName); @@ -3849,7 +3850,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param packageName The package to be re-enabled in the current profile. */ - public void enableSystemApp(ComponentName admin, String packageName) { + public void enableSystemApp(@NonNull ComponentName admin, String packageName) { if (mService != null) { try { mService.enableSystemApp(admin, packageName); @@ -3868,7 +3869,7 @@ public class DevicePolicyManager { * intent will be re-enabled in the current profile. * @return int The number of activities that matched the intent and were installed. */ - public int enableSystemApp(ComponentName admin, Intent intent) { + public int enableSystemApp(@NonNull ComponentName admin, Intent intent) { if (mService != null) { try { return mService.enableSystemAppWithIntent(admin, intent); @@ -3894,7 +3895,7 @@ public class DevicePolicyManager { * @param disabled The boolean indicating that account management will be disabled (true) or * enabled (false). */ - public void setAccountManagementDisabled(ComponentName admin, String accountType, + public void setAccountManagementDisabled(@NonNull ComponentName admin, String accountType, boolean disabled) { if (mService != null) { try { @@ -3950,7 +3951,7 @@ public class DevicePolicyManager { * @see DeviceAdminReceiver#onLockTaskModeExiting(Context, Intent) * @see UserManager#DISALLOW_CREATE_WINDOWS */ - public void setLockTaskPackages(ComponentName admin, String[] packages) + public void setLockTaskPackages(@NonNull ComponentName admin, String[] packages) throws SecurityException { if (mService != null) { try { @@ -3967,7 +3968,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @hide */ - public String[] getLockTaskPackages(ComponentName admin) { + public String[] getLockTaskPackages(@NonNull ComponentName admin) { if (mService != null) { try { return mService.getLockTaskPackages(admin); @@ -4024,7 +4025,7 @@ public class DevicePolicyManager { * @param setting The name of the setting to update. * @param value The value to update the setting to. */ - public void setGlobalSetting(ComponentName admin, String setting, String value) { + public void setGlobalSetting(@NonNull ComponentName admin, String setting, String value) { if (mService != null) { try { mService.setGlobalSetting(admin, setting, value); @@ -4052,7 +4053,7 @@ public class DevicePolicyManager { * @param setting The name of the setting to update. * @param value The value to update the setting to. */ - public void setSecureSetting(ComponentName admin, String setting, String value) { + public void setSecureSetting(@NonNull ComponentName admin, String setting, String value) { if (mService != null) { try { mService.setSecureSetting(admin, setting, value); @@ -4072,7 +4073,8 @@ public class DevicePolicyManager { * {@link RestrictionsReceiver}. If this param is null, * it removes the restrictions provider previously assigned. */ - public void setRestrictionsProvider(ComponentName admin, ComponentName provider) { + public void setRestrictionsProvider(@NonNull ComponentName admin, + @Nullable ComponentName provider) { if (mService != null) { try { mService.setRestrictionsProvider(admin, provider); @@ -4088,7 +4090,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param on {@code true} to mute master volume, {@code false} to turn mute off. */ - public void setMasterVolumeMuted(ComponentName admin, boolean on) { + public void setMasterVolumeMuted(@NonNull ComponentName admin, boolean on) { if (mService != null) { try { mService.setMasterVolumeMuted(admin, on); @@ -4104,7 +4106,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @return {@code true} if master volume is muted, {@code false} if it's not. */ - public boolean isMasterVolumeMuted(ComponentName admin) { + public boolean isMasterVolumeMuted(@NonNull ComponentName admin) { if (mService != null) { try { return mService.isMasterVolumeMuted(admin); @@ -4123,7 +4125,7 @@ public class DevicePolicyManager { * @param packageName package to change. * @param uninstallBlocked true if the user shouldn't be able to uninstall the package. */ - public void setUninstallBlocked(ComponentName admin, String packageName, + public void setUninstallBlocked(@NonNull ComponentName admin, String packageName, boolean uninstallBlocked) { if (mService != null) { try { @@ -4139,16 +4141,16 @@ public class DevicePolicyManager { * Requires the caller to be the profile owner if checking a specific admin's policy. * <p> * <strong>Note:</strong> Starting from {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}, the - * behavior of this API is changed such that passing <code>null</code> as the <code>admin</code> + * behavior of this API is changed such that passing {@code null} as the {@code admin} * parameter will return if any admin has blocked the uninstallation. Before L MR1, passing - * <code>null</code> will cause a NullPointerException to be raised. + * {@code null} will cause a NullPointerException to be raised. * - * @param admin The name of the admin component whose blocking policy will be checked, or null - * to check if any admin has blocked the uninstallation. + * @param admin The name of the admin component whose blocking policy will be checked, or + * {@code null} to check whether any admin has blocked the uninstallation. * @param packageName package to check. * @return true if uninstallation is blocked. */ - public boolean isUninstallBlocked(ComponentName admin, String packageName) { + public boolean isUninstallBlocked(@Nullable ComponentName admin, String packageName) { if (mService != null) { try { return mService.isUninstallBlocked(admin, packageName); @@ -4168,7 +4170,6 @@ public class DevicePolicyManager { * provides a different widget type. * <p> * <strong>Note:</strong> By default no widget provider package is white-listed. - * </p> * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param packageName The package from which widget providers are white-listed. @@ -4177,7 +4178,7 @@ public class DevicePolicyManager { * @see #removeCrossProfileWidgetProvider(android.content.ComponentName, String) * @see #getCrossProfileWidgetProviders(android.content.ComponentName) */ - public boolean addCrossProfileWidgetProvider(ComponentName admin, String packageName) { + public boolean addCrossProfileWidgetProvider(@NonNull ComponentName admin, String packageName) { if (mService != null) { try { return mService.addCrossProfileWidgetProvider(admin, packageName); @@ -4195,7 +4196,6 @@ public class DevicePolicyManager { * android.content.ComponentName, String)}. * <p> * <strong>Note:</strong> By default no widget provider package is white-listed. - * </p> * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param packageName The package from which widget providers are no longer @@ -4205,7 +4205,7 @@ public class DevicePolicyManager { * @see #addCrossProfileWidgetProvider(android.content.ComponentName, String) * @see #getCrossProfileWidgetProviders(android.content.ComponentName) */ - public boolean removeCrossProfileWidgetProvider(ComponentName admin, String packageName) { + public boolean removeCrossProfileWidgetProvider(@NonNull ComponentName admin, String packageName) { if (mService != null) { try { return mService.removeCrossProfileWidgetProvider(admin, packageName); @@ -4226,7 +4226,7 @@ public class DevicePolicyManager { * @see #addCrossProfileWidgetProvider(android.content.ComponentName, String) * @see #removeCrossProfileWidgetProvider(android.content.ComponentName, String) */ - public List<String> getCrossProfileWidgetProviders(ComponentName admin) { + public List<String> getCrossProfileWidgetProviders(@NonNull ComponentName admin) { if (mService != null) { try { List<String> providers = mService.getCrossProfileWidgetProviders(admin); @@ -4246,7 +4246,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param icon the bitmap to set as the photo. */ - public void setUserIcon(ComponentName admin, Bitmap icon) { + public void setUserIcon(@NonNull ComponentName admin, Bitmap icon) { try { mService.setUserIcon(admin, icon); } catch (RemoteException re) { @@ -4273,16 +4273,17 @@ public class DevicePolicyManager { * Called by device owners to set a local system update policy. When a new policy is set, * {@link #ACTION_SYSTEM_UPDATE_POLICY_CHANGED} is broadcasted. * - * @param who Which {@link DeviceAdminReceiver} this request is associated with. All components - * in the device owner package can set system update policies and the most recent policy takes + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. All + * components in the device owner package can set system update policies and the + * most recent policy takes * effect. - * @param policy the new policy, or null to clear the current policy. + * @param policy the new policy, or {@code null} to clear the current policy. * @see SystemUpdatePolicy */ - public void setSystemUpdatePolicy(ComponentName who, SystemUpdatePolicy policy) { + public void setSystemUpdatePolicy(@NonNull ComponentName admin, SystemUpdatePolicy policy) { if (mService != null) { try { - mService.setSystemUpdatePolicy(who, policy); + mService.setSystemUpdatePolicy(admin, policy); } catch (RemoteException re) { Log.w(TAG, "Error calling setSystemUpdatePolicy", re); } @@ -4292,7 +4293,7 @@ public class DevicePolicyManager { /** * Retrieve a local system update policy set previously by {@link #setSystemUpdatePolicy}. * - * @return The current policy object, or null if no policy is set. + * @return The current policy object, or {@code null} if no policy is set. */ public SystemUpdatePolicy getSystemUpdatePolicy() { if (mService != null) { @@ -4319,7 +4320,7 @@ public class DevicePolicyManager { * @return {@code false} if attempting to disable the keyguard while a lock password was in * place. {@code true} otherwise. */ - public boolean setKeyguardDisabled(ComponentName admin, boolean disabled) { + public boolean setKeyguardDisabled(@NonNull ComponentName admin, boolean disabled) { try { return mService.setKeyguardDisabled(admin, disabled); } catch (RemoteException re) { @@ -4339,7 +4340,7 @@ public class DevicePolicyManager { * @return {@code false} if attempting to disable the status bar failed. * {@code true} otherwise. */ - public boolean setStatusBarDisabled(ComponentName admin, boolean disabled) { + public boolean setStatusBarDisabled(@NonNull ComponentName admin, boolean disabled) { try { return mService.setStatusBarDisabled(admin, disabled); } catch (RemoteException re) { @@ -4377,7 +4378,8 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param activity The Activity to be started by default during user setup. */ - public void setPreferredSetupActivity(ComponentName admin, ComponentName activity) { + public void setPreferredSetupActivity(@NonNull ComponentName admin, + @NonNull ComponentName activity) { try { mService.setPreferredSetupActivity(admin, activity); } catch (RemoteException re) { @@ -4395,7 +4397,7 @@ public class DevicePolicyManager { * @param policy One of the policy constants {@link #PERMISSION_POLICY_PROMPT}, * {@link #PERMISSION_POLICY_AUTO_GRANT} and {@link #PERMISSION_POLICY_AUTO_DENY}. */ - public void setPermissionPolicy(ComponentName admin, int policy) { + public void setPermissionPolicy(@NonNull ComponentName admin, int policy) { try { mService.setPermissionPolicy(admin, policy); } catch (RemoteException re) { @@ -4409,7 +4411,7 @@ public class DevicePolicyManager { * @param admin Which profile or device owner this request is associated with. * @return the current policy for future permission requests. */ - public int getPermissionPolicy(ComponentName admin) { + public int getPermissionPolicy(@NonNull ComponentName admin) { try { return mService.getPermissionPolicy(admin); } catch (RemoteException re) { @@ -4439,7 +4441,7 @@ public class DevicePolicyManager { * @see #PERMISSION_GRANT_STATE_DEFAULT * @see #PERMISSION_GRANT_STATE_GRANTED */ - public boolean setPermissionGrantState(ComponentName admin, String packageName, + public boolean setPermissionGrantState(@NonNull ComponentName admin, String packageName, String permission, int grantState) { try { return mService.setPermissionGrantState(admin, packageName, permission, grantState); @@ -4466,7 +4468,7 @@ public class DevicePolicyManager { * @see #setPermissionGrantState(ComponentName, String, String, int) * @see PackageManager#checkPermission(String, String) */ - public int getPermissionGrantState(ComponentName admin, String packageName, + public int getPermissionGrantState(@NonNull ComponentName admin, String packageName, String permission) { try { return mService.getPermissionGrantState(admin, packageName, permission); diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index 254408a..a9328bc 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -32,4 +32,5 @@ interface IUsageStatsManager { UsageEvents queryEvents(long beginTime, long endTime, String callingPackage); void setAppInactive(String packageName, boolean inactive, int userId); boolean isAppInactive(String packageName, int userId); + void whitelistAppTemporarily(String packageName, long duration, int userId); } diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 34699d8..c74b0f2 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -16,6 +16,7 @@ package android.app.usage; +import android.annotation.SystemApi; import android.content.Context; import android.content.pm.ParceledListSlice; import android.os.RemoteException; @@ -245,4 +246,25 @@ public final class UsageStatsManager { // fall through } } + + /** + * {@hide} + * Temporarily whitelist the specified app for a short duration. This is to allow an app + * receiving a high priority message to be able to access the network and acquire wakelocks + * even if the device is in power-save mode or the app is currently considered inactive. + * The caller must hold the CHANGE_DEVICE_IDLE_TEMP_WHITELIST permission. + * @param packageName The package name of the app to whitelist. + * @param duration Duration to whitelist the app for, in milliseconds. It is recommended that + * this be limited to 10s of seconds. Requested duration will be clamped to a few minutes. + * @param user The user for whom the package should be whitelisted. Passing in a user that is + * not the same as the caller's process will require the INTERACT_ACROSS_USERS permission. + * @see #isAppInactive(String) + */ + @SystemApi + public void whitelistAppTemporarily(String packageName, long duration, UserHandle user) { + try { + mService.whitelistAppTemporarily(packageName, duration, user.getIdentifier()); + } catch (RemoteException re) { + } + } } diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index b22b914..8107a97 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -410,6 +410,7 @@ public final class BluetoothAdapter { * Broadcast Action: The Bluetooth adapter state has changed in LE only mode. * @hide */ + @SystemApi public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; @@ -620,17 +621,18 @@ public final class BluetoothAdapter { * @return true if the local Bluetooth LE adapter is turned on * @hide */ - public boolean isLeEnabled() { - final int state = getLeState(); - if (state == BluetoothAdapter.STATE_ON) { - if (DBG) Log.d (TAG, "STATE_ON"); - } else if (state == BluetoothAdapter.STATE_BLE_ON) { - if (DBG) Log.d (TAG, "STATE_BLE_ON"); - } else { - if (DBG) Log.d (TAG, "STATE_OFF"); - return false; - } - return true; + @SystemApi + public boolean isLeEnabled() { + final int state = getLeState(); + if (state == BluetoothAdapter.STATE_ON) { + if (DBG) Log.d (TAG, "STATE_ON"); + } else if (state == BluetoothAdapter.STATE_BLE_ON) { + if (DBG) Log.d (TAG, "STATE_BLE_ON"); + } else { + if (DBG) Log.d (TAG, "STATE_OFF"); + return false; + } + return true; } /** @@ -680,6 +682,7 @@ public final class BluetoothAdapter { * immediate error * @hide */ + @SystemApi public boolean disableBLE() { if (!isBleScanAlwaysAvailable()) return false; @@ -742,6 +745,7 @@ public final class BluetoothAdapter { * immediate error * @hide */ + @SystemApi public boolean enableBLE() { if (!isBleScanAlwaysAvailable()) return false; diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 26a91e4..dcf06d8 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -567,19 +567,16 @@ public final class BluetoothDevice implements Parcelable { /** * No preferrence of physical transport for GATT connections to remote dual-mode devices - * @hide */ public static final int TRANSPORT_AUTO = 0; /** * Prefer BR/EDR transport for GATT connections to remote dual-mode devices - * @hide */ public static final int TRANSPORT_BREDR = 1; /** * Prefer LE transport for GATT connections to remote dual-mode devices - * @hide */ public static final int TRANSPORT_LE = 2; @@ -1564,7 +1561,6 @@ public final class BluetoothDevice implements Parcelable { * {@link BluetoothDevice#TRANSPORT_AUTO} or * {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE} * @throws IllegalArgumentException if callback is null - * @hide */ public BluetoothGatt connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport) { diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java index eb6166a..744f942 100644 --- a/core/java/android/bluetooth/BluetoothPan.java +++ b/core/java/android/bluetooth/BluetoothPan.java @@ -138,7 +138,6 @@ public final class BluetoothPan implements BluetoothProfile { } if (VDBG) Log.d(TAG, "BluetoothPan() call bindService"); doBind(); - if (VDBG) Log.d(TAG, "BluetoothPan(), bindService called"); } boolean doBind() { @@ -185,12 +184,22 @@ public final class BluetoothPan implements BluetoothProfile { final private IBluetoothStateChangeCallback mStateChangeCallback = new IBluetoothStateChangeCallback.Stub() { @Override - public void onBluetoothStateChange(boolean on) throws RemoteException { - //Handle enable request to bind again. + public void onBluetoothStateChange(boolean on) { + // Handle enable request to bind again. + Log.d(TAG, "onBluetoothStateChange on: " + on); if (on) { - Log.d(TAG, "onBluetoothStateChange(on) call bindService"); - doBind(); - if (VDBG) Log.d(TAG, "BluetoothPan(), bindService called"); + try { + if (mPanService == null) { + if (VDBG) Log.d(TAG, "onBluetoothStateChange calling doBind()"); + doBind(); + } + + } catch (IllegalStateException e) { + Log.e(TAG,"onBluetoothStateChange: could not bind to PAN service: ", e); + + } catch (SecurityException e) { + Log.e(TAG,"onBluetoothStateChange: could not bind to PAN service: ", e); + } } else { if (VDBG) Log.d(TAG,"Unbinding service..."); synchronized (mConnection) { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 62a1617..c01ce4f 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1387,6 +1387,11 @@ public class Intent implements Parcelable, Cloneable { * <p> * Output: If {@link #EXTRA_RETURN_RESULT}, returns whether the install * succeeded. + * <p> + * <strong>Note:</strong>If your app is targeting API level higher than 22 you + * need to hold {@link android.Manifest.permission#REQUEST_INSTALL_PACKAGES} + * in order to launch the application installer. + * </p> * * @see #EXTRA_INSTALLER_PACKAGE_NAME * @see #EXTRA_NOT_UNKNOWN_SOURCE diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 96bb2ee..9fb6f4d 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -373,6 +373,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_EXTRACT_NATIVE_LIBS = 1<<28; /** + * Value for {@link #flags}: {@code true} when the application's rendering + * should be hardware accelerated. + */ + public static final int FLAG_HARDWARE_ACCELERATED = 1<<29; + + /** * Value for {@link #flags}: true if code from this application will need to be * loaded into other applications' processes. On devices that support multiple * instruction sets, this implies the code might be loaded into a process that's @@ -648,11 +654,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public int installLocation = PackageInfo.INSTALL_LOCATION_UNSPECIFIED; - /** - * True when the application's rendering should be hardware accelerated. - */ - public boolean hardwareAccelerated; - public void dump(Printer pw, String prefix) { super.dumpFront(pw, prefix); if (className != null) { @@ -692,7 +693,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } pw.println(prefix + "enabled=" + enabled + " targetSdkVersion=" + targetSdkVersion + " versionCode=" + versionCode); - pw.println(prefix + "hardwareAccelerated=" + hardwareAccelerated); if (manageSpaceActivityName != null) { pw.println(prefix + "manageSpaceActivityName="+manageSpaceActivityName); } @@ -784,7 +784,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { descriptionRes = orig.descriptionRes; uiOptions = orig.uiOptions; backupAgentName = orig.backupAgentName; - hardwareAccelerated = orig.hardwareAccelerated; fullBackupContent = orig.fullBackupContent; } @@ -838,7 +837,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeString(backupAgentName); dest.writeInt(descriptionRes); dest.writeInt(uiOptions); - dest.writeInt(hardwareAccelerated ? 1 : 0); dest.writeInt(fullBackupContent); } @@ -891,7 +889,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { backupAgentName = source.readString(); descriptionRes = source.readInt(); uiOptions = source.readInt(); - hardwareAccelerated = source.readInt() != 0; fullBackupContent = source.readInt(); } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 596c0e4..755eb5b 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -2530,7 +2530,9 @@ public class PackageParser { owner.baseHardwareAccelerated = sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated, owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH); - ai.hardwareAccelerated = owner.baseHardwareAccelerated; + if (owner.baseHardwareAccelerated) { + ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED; + } if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_hasCode, diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java index 14bfac5..579634f 100644 --- a/core/java/android/content/res/ColorStateList.java +++ b/core/java/android/content/res/ColorStateList.java @@ -382,6 +382,14 @@ public class ColorStateList implements Parcelable { defaultAlphaMod = 1.0f; } + // Extract the theme attributes, if any, before attempting to + // read from the typed array. This prevents a crash if we have + // unresolved attrs. + themeAttrsList[i] = a.extractThemeAttrs(themeAttrsList[i]); + if (themeAttrsList[i] != null) { + hasUnresolvedAttrs = true; + } + final int baseColor = a.getColor( R.styleable.ColorStateListItem_color, mColors[i]); final float alphaMod = a.getFloat( @@ -391,12 +399,6 @@ public class ColorStateList implements Parcelable { // Account for any configuration changes. mChangingConfigurations |= a.getChangingConfigurations(); - // Extract the theme attributes, if any. - themeAttrsList[i] = a.extractThemeAttrs(themeAttrsList[i]); - if (themeAttrsList[i] != null) { - hasUnresolvedAttrs = true; - } - a.recycle(); } } diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index 1fca920..8bcd5d1 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -160,7 +160,6 @@ public class TypedArray { final TypedValue v = mValue; if (getValueAt(index, v)) { - StrictMode.noteResourceMismatch(v); return v.coerceToString(); } @@ -181,6 +180,7 @@ public class TypedArray { * not be coerced to a string. * @throws RuntimeException if the TypedArray has already been recycled. */ + @Nullable public String getString(int index) { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); @@ -197,7 +197,6 @@ public class TypedArray { final TypedValue v = mValue; if (getValueAt(index, v)) { - StrictMode.noteResourceMismatch(v); final CharSequence cs = v.coerceToString(); return cs != null ? cs.toString() : null; } @@ -271,7 +270,6 @@ public class TypedArray { final TypedValue v = mValue; if (getValueAt(index, v)) { - StrictMode.noteResourceMismatch(v); final CharSequence cs = v.coerceToString(); return cs != null ? cs.toString() : null; } diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java index e61664c..227066d 100644 --- a/core/java/android/database/DatabaseUtils.java +++ b/core/java/android/database/DatabaseUtils.java @@ -270,7 +270,7 @@ public class DatabaseUtils { window.setStartPosition(position); window.setNumColumns(numColumns); if (cursor.moveToPosition(position)) { - do { + rowloop: do { if (!window.allocRow()) { break; } @@ -307,7 +307,7 @@ public class DatabaseUtils { } if (!success) { window.freeLastRow(); - break; + break rowloop; } } position += 1; diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java index 2bc0f9b..906c2a1 100644 --- a/core/java/android/hardware/SensorEvent.java +++ b/core/java/android/hardware/SensorEvent.java @@ -312,7 +312,7 @@ public class SensorEvent { * </p> * * <p> - * values[2]: Roll, rotation around the x-axis (-90 to 90) + * values[2]: Roll, rotation around the y-axis (-90 to 90) * increasing as the device moves clockwise. * </p> * </ul> @@ -325,6 +325,8 @@ public class SensorEvent { * * <p> * <b>Note:</b> This sensor type exists for legacy reasons, please use + * {@link android.hardware.Sensor#TYPE_ROTATION_VECTOR + * rotation vector sensor type} and * {@link android.hardware.SensorManager#getRotationMatrix * getRotationMatrix()} in conjunction with * {@link android.hardware.SensorManager#remapCoordinateSystem diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index 861969e..fda889f 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -967,8 +967,9 @@ public abstract class SensorManager { * TYPE_MAGNETIC_FIELD}. * * @return <code>true</code> on success, <code>false</code> on failure (for - * instance, if the device is in free fall). On failure the output - * matrices are not modified. + * instance, if the device is in free fall). Free fall is defined as + * condition when the magnitude of the gravity is less than 1/10 of + * the nominal value. On failure the output matrices are not modified. * * @see #getInclination(float[]) * @see #getOrientation(float[], float[]) @@ -981,6 +982,15 @@ public abstract class SensorManager { float Ax = gravity[0]; float Ay = gravity[1]; float Az = gravity[2]; + + final float normsqA = (Ax*Ax + Ay*Ay + Az*Az); + final float g = 9.81f; + final float freeFallGravitySquared = 0.01f * g * g; + if (normsqA < freeFallGravitySquared) { + // gravity less than 10% of normal value + return false; + } + final float Ex = geomagnetic[0]; final float Ey = geomagnetic[1]; final float Ez = geomagnetic[2]; @@ -988,6 +998,7 @@ public abstract class SensorManager { float Hy = Ez*Ax - Ex*Az; float Hz = Ex*Ay - Ey*Ax; final float normH = (float)Math.sqrt(Hx*Hx + Hy*Hy + Hz*Hz); + if (normH < 0.1f) { // device is close to free fall (or in space?), or close to // magnetic north pole. Typical values are > 100. @@ -1117,12 +1128,12 @@ public abstract class SensorManager { * returned by {@link #getRotationMatrix}. * * @param X - * defines on which world axis and direction the X axis of the device - * is mapped. + * defines the axis of the new cooridinate system that coincide with the X axis of the + * original coordinate system. * * @param Y - * defines on which world axis and direction the Y axis of the device - * is mapped. + * defines the axis of the new cooridinate system that coincide with the Y axis of the + * original coordinate system. * * @param outR * the transformed rotation matrix. inR and outR should not be the same @@ -1219,27 +1230,18 @@ public abstract class SensorManager { * <p> * When it returns, the array values is filled with the result: * <ul> - * <li>values[0]: <i>azimuth</i>, rotation around the Z axis.</li> - * <li>values[1]: <i>pitch</i>, rotation around the X axis.</li> + * <li>values[0]: <i>azimuth</i>, rotation around the -Z axis, + * i.e. the opposite direction of Z axis.</li> + * <li>values[1]: <i>pitch</i>, rotation around the -X axis, + * i.e the opposite direction of X axis.</li> * <li>values[2]: <i>roll</i>, rotation around the Y axis.</li> * </ul> - * <p>The reference coordinate-system used is different from the world - * coordinate-system defined for the rotation matrix:</p> - * <ul> - * <li>X is defined as the vector product <b>Y.Z</b> (It is tangential to - * the ground at the device's current location and roughly points West).</li> - * <li>Y is tangential to the ground at the device's current location and - * points towards the magnetic North Pole.</li> - * <li>Z points towards the center of the Earth and is perpendicular to the ground.</li> - * </ul> - * - * <p> - * <center><img src="../../../images/axis_globe_inverted.png" - * alt="Inverted world coordinate-system diagram." border="0" /></center> - * </p> * <p> + * Applying these three intrinsic rotations in azimuth, pitch and roll order transforms + * identity matrix to the rotation matrix given in input R. * All three angles above are in <b>radians</b> and <b>positive</b> in the - * <b>counter-clockwise</b> direction. + * <b>counter-clockwise</b> direction. Range of output is: azimuth from -π to π, + * pitch from -π/2 to π/2 and roll from -π to π. * * @param R * rotation matrix see {@link #getRotationMatrix}. @@ -1275,6 +1277,7 @@ public abstract class SensorManager { values[1] = (float)Math.asin(-R[9]); values[2] = (float)Math.atan2(-R[8], R[10]); } + return values; } @@ -1314,9 +1317,9 @@ public abstract class SensorManager { /** Helper function to compute the angle change between two rotation matrices. * Given a current rotation matrix (R) and a previous rotation matrix - * (prevR) computes the rotation around the z,x, and y axes which + * (prevR) computes the intrinsic rotation around the z, x, and y axes which * transforms prevR to R. - * outputs a 3 element vector containing the z,x, and y angle + * outputs a 3 element vector containing the z, x, and y angle * change at indexes 0, 1, and 2 respectively. * <p> Each input matrix is either as a 3x3 or 4x4 row-major matrix * depending on the length of the passed array: @@ -1333,9 +1336,13 @@ public abstract class SensorManager { * | R[ 8] R[ 9] R[10] R[11] | * \ R[12] R[13] R[14] R[15] / *</pre> + * + * See {@link #getOrientation} for more detailed definition of the output. + * * @param R current rotation matrix * @param prevR previous rotation matrix - * @param angleChange an an array of floats (z, x, and y) in which the angle change is stored + * @param angleChange an an array of floats (z, x, and y) in which the angle change + * (in radians) is stored */ public static void getAngleChange( float[] angleChange, float[] R, float[] prevR) { diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java index b3e7cfc..c22ee5f 100644 --- a/core/java/android/hardware/camera2/CameraCaptureSession.java +++ b/core/java/android/hardware/camera2/CameraCaptureSession.java @@ -654,16 +654,22 @@ public abstract class CameraCaptureSession implements AutoCloseable { /** * This method is called when the camera device has started capturing - * the output image for the request, at the beginning of image exposure. + * the output image for the request, at the beginning of image exposure, or + * when the camera device has started processing an input image for a reprocess + * request. * - * <p>This callback is invoked right as the capture of a frame begins, - * so it is the most appropriate time for playing a shutter sound, - * or triggering UI indicators of capture.</p> + * <p>For a regular capture request, this callback is invoked right as + * the capture of a frame begins, so it is the most appropriate time + * for playing a shutter sound, or triggering UI indicators of capture.</p> * * <p>The request that is being used for this capture is provided, along - * with the actual timestamp for the start of exposure. This timestamp - * matches the timestamp that will be included in - * {@link CaptureResult#SENSOR_TIMESTAMP the result timestamp field}, + * with the actual timestamp for the start of exposure. For a reprocess + * request, this timestamp will be the input image's start of exposure + * which matches {@link CaptureResult#SENSOR_TIMESTAMP the result timestamp field} + * of the {@link TotalCaptureResult} that was used to + * {@link CameraDevice#createReprocessCaptureRequest create the reprocess request}. + * This timestamp matches the timestamps that will be + * included in {@link CaptureResult#SENSOR_TIMESTAMP the result timestamp field}, * and in the buffers sent to each output Surface. These buffer * timestamps are accessible through, for example, * {@link android.media.Image#getTimestamp() Image.getTimestamp()} or @@ -679,7 +685,9 @@ public abstract class CameraCaptureSession implements AutoCloseable { * * @param session the session returned by {@link CameraDevice#createCaptureSession} * @param request the request for the capture that just begun - * @param timestamp the timestamp at start of capture, in nanoseconds. + * @param timestamp the timestamp at start of capture for a regular request, or + * the timestamp at the input image's start of capture for a + * reprocess request, in nanoseconds. * @param frameNumber the frame number for this capture * * @see android.media.MediaActionSound diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 4fe257c..d5867a9 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -1068,20 +1068,35 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri /** * <p>The correction coefficients to correct for this camera device's - * radial lens distortion.</p> - * <p>Three cofficients <code>[kappa_1, kappa_2, kappa_3]</code> that - * can be used to correct the lens's radial geometric - * distortion with the mapping equations:</p> - * <pre><code> x_c = x_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) - * y_c = y_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) + * radial and tangential lens distortion.</p> + * <p>Three radial distortion coefficients <code>[kappa_1, kappa_2, + * kappa_3]</code> and two tangential distortion coefficients + * <code>[kappa_4, kappa_5]</code> that can be used to correct the + * lens's geometric distortion with the mapping equations:</p> + * <pre><code> x_c = x_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) + + * kappa_4 * (2 * x_i * y_i) + kappa_5 * ( r^2 + 2 * x_i^2 ) + * y_c = y_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) + + * kappa_5 * (2 * x_i * y_i) + kappa_4 * ( r^2 + 2 * y_i^2 ) * </code></pre> - * <p>where <code>[x_i, y_i]</code> are normalized coordinates with <code>(0,0)</code> - * at the lens optical center, and <code>[-1, 1]</code> are the edges of - * the active pixel array; and where <code>[x_c, y_c]</code> are the - * corrected normalized coordinates with radial distortion - * removed; and <code>r^2 = x_i^2 + y_i^2</code>.</p> + * <p>Here, <code>[x_c, y_c]</code> are the coordinates to sample in the + * input image that correspond to the pixel values in the + * corrected image at the coordinate <code>[x_i, y_i]</code>:</p> + * <pre><code> correctedImage(x_i, y_i) = sample_at(x_c, y_c, inputImage) + * </code></pre> + * <p>The pixel coordinates are defined in a normalized + * coordinate system related to the + * android.lens.intrinsicCalibration calibration fields. + * Both <code>[x_i, y_i]</code> and <code>[x_c, y_c]</code> have <code>(0,0)</code> at the + * lens optical center <code>[c_x, c_y]</code>. The maximum magnitudes + * of both x and y coordinates are normalized to be 1 at the + * edge further from the optical center, so the range + * for both dimensions is <code>-1 <= x <= 1</code>.</p> + * <p>Finally, <code>r</code> represents the radial distance from the + * optical center, <code>r^2 = x_i^2 + y_i^2</code>, and its magnitude + * is therefore no larger than <code>|r| <= sqrt(2)</code>.</p> + * <p>The distortion model used is the Brown-Conrady model.</p> * <p><b>Units</b>: - * Coefficients for a 6th-degree even radial polynomial.</p> + * Unitless coefficients.</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> */ @PublicKey diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 20e1610..0f002a9 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -56,7 +56,7 @@ import java.util.ArrayList; public final class CameraManager { private static final String TAG = "CameraManager"; - private final boolean DEBUG; + private final boolean DEBUG = false; private static final int USE_CALLING_UID = -1; @@ -73,7 +73,6 @@ public final class CameraManager { * @hide */ public CameraManager(Context context) { - DEBUG = Log.isLoggable(TAG, Log.DEBUG); synchronized(mLock) { mContext = context; } @@ -722,7 +721,7 @@ public final class CameraManager { implements IBinder.DeathRecipient { private static final String TAG = "CameraManagerGlobal"; - private final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private final boolean DEBUG = false; // Singleton instance private static final CameraManagerGlobal gCameraManager = diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index cf091a9..ac29f80 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -51,7 +51,7 @@ import java.util.List; public abstract class CameraMetadata<TKey> { private static final String TAG = "CameraMetadataAb"; - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private static final boolean DEBUG = false; /** * Set a camera metadata field to a value. The field definitions can be @@ -131,7 +131,7 @@ public abstract class CameraMetadata<TKey> { CameraMetadata<TKey> instance, int[] filterTags) { - if (VERBOSE) Log.v(TAG, "getKeysStatic for " + type); + if (DEBUG) Log.v(TAG, "getKeysStatic for " + type); // TotalCaptureResult does not have any of the keys on it, use CaptureResult instead if (type.equals(TotalCaptureResult.class)) { @@ -163,10 +163,10 @@ public abstract class CameraMetadata<TKey> { if (shouldKeyBeAdded(key, field, filterTags)) { keyList.add(key); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "getKeysStatic - key was added - " + key); } - } else if (VERBOSE) { + } else if (DEBUG) { Log.v(TAG, "getKeysStatic - key was filtered - " + key); } } diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index f4017d0..df6c986 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -2649,20 +2649,35 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { /** * <p>The correction coefficients to correct for this camera device's - * radial lens distortion.</p> - * <p>Three cofficients <code>[kappa_1, kappa_2, kappa_3]</code> that - * can be used to correct the lens's radial geometric - * distortion with the mapping equations:</p> - * <pre><code> x_c = x_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) - * y_c = y_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) + * radial and tangential lens distortion.</p> + * <p>Three radial distortion coefficients <code>[kappa_1, kappa_2, + * kappa_3]</code> and two tangential distortion coefficients + * <code>[kappa_4, kappa_5]</code> that can be used to correct the + * lens's geometric distortion with the mapping equations:</p> + * <pre><code> x_c = x_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) + + * kappa_4 * (2 * x_i * y_i) + kappa_5 * ( r^2 + 2 * x_i^2 ) + * y_c = y_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 ) + + * kappa_5 * (2 * x_i * y_i) + kappa_4 * ( r^2 + 2 * y_i^2 ) * </code></pre> - * <p>where <code>[x_i, y_i]</code> are normalized coordinates with <code>(0,0)</code> - * at the lens optical center, and <code>[-1, 1]</code> are the edges of - * the active pixel array; and where <code>[x_c, y_c]</code> are the - * corrected normalized coordinates with radial distortion - * removed; and <code>r^2 = x_i^2 + y_i^2</code>.</p> + * <p>Here, <code>[x_c, y_c]</code> are the coordinates to sample in the + * input image that correspond to the pixel values in the + * corrected image at the coordinate <code>[x_i, y_i]</code>:</p> + * <pre><code> correctedImage(x_i, y_i) = sample_at(x_c, y_c, inputImage) + * </code></pre> + * <p>The pixel coordinates are defined in a normalized + * coordinate system related to the + * android.lens.intrinsicCalibration calibration fields. + * Both <code>[x_i, y_i]</code> and <code>[x_c, y_c]</code> have <code>(0,0)</code> at the + * lens optical center <code>[c_x, c_y]</code>. The maximum magnitudes + * of both x and y coordinates are normalized to be 1 at the + * edge further from the optical center, so the range + * for both dimensions is <code>-1 <= x <= 1</code>.</p> + * <p>Finally, <code>r</code> represents the radial distance from the + * optical center, <code>r^2 = x_i^2 + y_i^2</code>, and its magnitude + * is therefore no larger than <code>|r| <= sqrt(2)</code>.</p> + * <p>The distortion model used is the Brown-Conrady model.</p> * <p><b>Units</b>: - * Coefficients for a 6th-degree even radial polynomial.</p> + * Unitless coefficients.</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> */ @PublicKey @@ -2988,6 +3003,10 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * timestamps measure time in the same timebase as {@link android.os.SystemClock#elapsedRealtimeNanos }, and they can * be compared to other timestamps from other subsystems that * are using that base.</p> + * <p>For reprocessing, the timestamp will match the start of exposure of + * the input image, i.e. {@link CaptureResult#SENSOR_TIMESTAMP the + * timestamp} in the TotalCaptureResult that was used to create the + * reprocess capture request.</p> * <p><b>Units</b>: Nanoseconds</p> * <p><b>Range of valid values:</b><br> * > 0</p> diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java index 7f4a76c..7a39dd5 100644 --- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java @@ -38,7 +38,7 @@ import static com.android.internal.util.Preconditions.*; public class CameraCaptureSessionImpl extends CameraCaptureSession { private static final String TAG = "CameraCaptureSession"; - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private static final boolean DEBUG = false; /** Simple integer ID for session for debugging */ private final int mId; @@ -124,7 +124,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { if (configureSuccess) { mStateCallback.onConfigured(this); - if (VERBOSE) Log.v(TAG, mIdString + "Created session successfully"); + if (DEBUG) Log.v(TAG, mIdString + "Created session successfully"); mConfigureSuccess = true; } else { mStateCallback.onConfigureFailed(this); @@ -160,7 +160,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { handler = checkHandler(handler, callback); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, mIdString + "capture - request " + request + ", callback " + callback + " handler " + handler); } @@ -194,7 +194,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { handler = checkHandler(handler, callback); - if (VERBOSE) { + if (DEBUG) { CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]); Log.v(TAG, mIdString + "captureBurst - requests " + Arrays.toString(requestArray) + ", callback " + callback + " handler " + handler); @@ -218,7 +218,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { handler = checkHandler(handler, callback); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, mIdString + "setRepeatingRequest - request " + request + ", callback " + callback + " handler" + " " + handler); } @@ -247,7 +247,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { handler = checkHandler(handler, callback); - if (VERBOSE) { + if (DEBUG) { CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]); Log.v(TAG, mIdString + "setRepeatingBurst - requests " + Arrays.toString(requestArray) + ", callback " + callback + " handler" + "" + handler); @@ -261,7 +261,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { public synchronized void stopRepeating() throws CameraAccessException { checkNotClosed(); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, mIdString + "stopRepeating"); } @@ -272,7 +272,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { public synchronized void abortCaptures() throws CameraAccessException { checkNotClosed(); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, mIdString + "abortCaptures"); } @@ -325,7 +325,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { * but this would introduce nondeterministic behavior. */ - if (VERBOSE) Log.v(TAG, mIdString + "replaceSessionClose"); + if (DEBUG) Log.v(TAG, mIdString + "replaceSessionClose"); // Set up fast shutdown. Possible alternative paths: // - This session is active, so close() below starts the shutdown drain @@ -345,11 +345,11 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { public synchronized void close() { if (mClosed) { - if (VERBOSE) Log.v(TAG, mIdString + "close - reentering"); + if (DEBUG) Log.v(TAG, mIdString + "close - reentering"); return; } - if (VERBOSE) Log.v(TAG, mIdString + "close - first time"); + if (DEBUG) Log.v(TAG, mIdString + "close - first time"); mClosed = true; @@ -498,7 +498,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { @Override public void onDisconnected(CameraDevice camera) { - if (VERBOSE) Log.v(TAG, mIdString + "onDisconnected"); + if (DEBUG) Log.v(TAG, mIdString + "onDisconnected"); close(); } @@ -513,14 +513,14 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { mIdleDrainer.taskStarted(); mActive = true; - if (VERBOSE) Log.v(TAG, mIdString + "onActive"); + if (DEBUG) Log.v(TAG, mIdString + "onActive"); mStateCallback.onActive(session); } @Override public void onIdle(CameraDevice camera) { boolean isAborting; - if (VERBOSE) Log.v(TAG, mIdString + "onIdle"); + if (DEBUG) Log.v(TAG, mIdString + "onIdle"); synchronized (session) { isAborting = mAborting; @@ -562,17 +562,17 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { // TODO: Queue captures during abort instead of failing them // since the app won't be able to distinguish the two actives // Don't signal the application since there's no clean mapping here - if (VERBOSE) Log.v(TAG, mIdString + "onBusy"); + if (DEBUG) Log.v(TAG, mIdString + "onBusy"); } @Override public void onUnconfigured(CameraDevice camera) { - if (VERBOSE) Log.v(TAG, mIdString + "onUnconfigured"); + if (DEBUG) Log.v(TAG, mIdString + "onUnconfigured"); } @Override public void onSurfacePrepared(Surface surface) { - if (VERBOSE) Log.v(TAG, mIdString + "onPrepared"); + if (DEBUG) Log.v(TAG, mIdString + "onPrepared"); mStateCallback.onSurfacePrepared(session, surface); } @@ -631,7 +631,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { * If the camera is already "IDLE" and no aborts are pending, * then the drain immediately finishes. */ - if (VERBOSE) Log.v(TAG, mIdString + "onSequenceDrained"); + if (DEBUG) Log.v(TAG, mIdString + "onSequenceDrained"); // Fire session close as soon as all sequences are complete. @@ -652,7 +652,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { private class AbortDrainListener implements TaskDrainer.DrainListener { @Override public void onDrained() { - if (VERBOSE) Log.v(TAG, mIdString + "onAbortDrained"); + if (DEBUG) Log.v(TAG, mIdString + "onAbortDrained"); synchronized (CameraCaptureSessionImpl.this) { /* * Any queued aborts have now completed. @@ -676,7 +676,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { private class IdleDrainListener implements TaskDrainer.DrainListener { @Override public void onDrained() { - if (VERBOSE) Log.v(TAG, mIdString + "onIdleDrained"); + if (DEBUG) Log.v(TAG, mIdString + "onIdleDrained"); // Take device lock before session lock so that we can call back into device // without causing a deadlock @@ -690,7 +690,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { * * This operation is idempotent; a session will not be closed twice. */ - if (VERBOSE) + if (DEBUG) Log.v(TAG, mIdString + "Session drain complete, skip unconfigure: " + mSkipUnconfigure); @@ -712,7 +712,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { // TODO: call onError instead of onClosed if this happens } catch (IllegalStateException e) { // Camera is already closed, so nothing left to do - if (VERBOSE) Log.v(TAG, mIdString + + if (DEBUG) Log.v(TAG, mIdString + "Camera was already closed or busy, skipping unconfigure"); } diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index c4e8b15..e60e266 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -58,7 +58,7 @@ import java.util.TreeMap; */ public class CameraDeviceImpl extends CameraDevice { private final String TAG; - private final boolean DEBUG; + private final boolean DEBUG = false; private static final int REQUEST_ID_NONE = -1; @@ -240,7 +240,6 @@ public class CameraDeviceImpl extends CameraDevice { tag = tag.substring(0, MAX_TAG_LEN); } TAG = tag; - DEBUG = Log.isLoggable(TAG, Log.DEBUG); Integer partialCount = mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT); diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index b8b7d12..10dd8ae 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -222,7 +222,8 @@ public class CameraMetadataNative implements Parcelable { } private static final String TAG = "CameraMetadataJV"; - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private static final boolean DEBUG = false; + // this should be in sync with HAL_PIXEL_FORMAT_BLOB defined in graphics.h public static final int NATIVE_JPEG_FORMAT = 0x21; @@ -1197,7 +1198,7 @@ public class CameraMetadataNative implements Parcelable { @SuppressWarnings({ "unchecked", "rawtypes" }) private static void registerAllMarshalers() { - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "Shall register metadata marshalers"); } @@ -1234,7 +1235,7 @@ public class CameraMetadataNative implements Parcelable { for (MarshalQueryable query : queryList) { MarshalRegistry.registerMarshalQueryable(query); } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "Registered metadata marshalers"); } } diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java index 89e2d98..2c2ad1c 100644 --- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java +++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java @@ -41,7 +41,7 @@ import android.util.Log; */ public class CameraDeviceState { private static final String TAG = "CameraDeviceState"; - private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG); + private static final boolean DEBUG = false; private static final int STATE_ERROR = 0; private static final int STATE_UNCONFIGURED = 1; diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java index edad00f..bc0a3a8 100644 --- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java +++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java @@ -61,7 +61,7 @@ import java.util.List; public class CameraDeviceUserShim implements ICameraDeviceUser { private static final String TAG = "CameraDeviceUserShim"; - private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG); + private static final boolean DEBUG = false; private static final int OPEN_CAMERA_TIMEOUT_MS = 5000; // 5 sec (same as api1 cts timeout) private final LegacyCameraDevice mLegacyDevice; diff --git a/core/java/android/hardware/camera2/legacy/CaptureCollector.java b/core/java/android/hardware/camera2/legacy/CaptureCollector.java index 8404e86..eb48a01 100644 --- a/core/java/android/hardware/camera2/legacy/CaptureCollector.java +++ b/core/java/android/hardware/camera2/legacy/CaptureCollector.java @@ -34,7 +34,7 @@ import java.util.concurrent.locks.ReentrantLock; public class CaptureCollector { private static final String TAG = "CaptureCollector"; - private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG); + private static final boolean DEBUG = false; private static final int FLAG_RECEIVED_JPEG = 1; private static final int FLAG_RECEIVED_JPEG_TS = 2; diff --git a/core/java/android/hardware/camera2/legacy/GLThreadManager.java b/core/java/android/hardware/camera2/legacy/GLThreadManager.java index b160d2a..152d82d 100644 --- a/core/java/android/hardware/camera2/legacy/GLThreadManager.java +++ b/core/java/android/hardware/camera2/legacy/GLThreadManager.java @@ -35,7 +35,7 @@ import static com.android.internal.util.Preconditions.*; */ public class GLThreadManager { private final String TAG; - private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG); + private static final boolean DEBUG = false; private static final int MSG_NEW_CONFIGURATION = 1; private static final int MSG_NEW_FRAME = 2; diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java index b5a019d..098c2d8 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java +++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java @@ -59,10 +59,9 @@ import static com.android.internal.util.Preconditions.*; * </p> */ public class LegacyCameraDevice implements AutoCloseable { - public static final String DEBUG_PROP = "HAL1ShimLogging"; private final String TAG; - private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG); + private static final boolean DEBUG = false; private final int mCameraId; private final CameraCharacteristics mStaticCharacteristics; private final ICameraDeviceCallbacks mDeviceCallbacks; diff --git a/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java b/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java index e576beb..882a7f4 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java @@ -44,7 +44,7 @@ import static com.android.internal.util.Preconditions.*; @SuppressWarnings("deprecation") public class LegacyFaceDetectMapper { private static String TAG = "LegacyFaceDetectMapper"; - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private static final boolean DEBUG = false; private final Camera mCamera; /** Is the camera capable of face detection? */ @@ -97,7 +97,7 @@ public class LegacyFaceDetectMapper { } } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "onFaceDetection - read " + lengthFaces + " faces"); } } @@ -170,13 +170,13 @@ public class LegacyFaceDetectMapper { if (enableFaceDetect) { mCamera.startFaceDetection(); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "processFaceDetectMode - start face detection"); } } else { mCamera.stopFaceDetection(); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "processFaceDetectMode - stop face detection"); } @@ -248,7 +248,7 @@ public class LegacyFaceDetectMapper { } } - if (VERBOSE && previousFaces != faces) { // Log only in verbose and IF the faces changed + if (DEBUG && previousFaces != faces) { // Log only in verbose and IF the faces changed Log.v(TAG, "mapResultFaces - changed to " + ListUtils.listToString(convertedFaces)); } diff --git a/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java index d5ec71a..d33c09e 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java @@ -38,7 +38,7 @@ import static com.android.internal.util.Preconditions.*; @SuppressWarnings("deprecation") public class LegacyFocusStateMapper { private static String TAG = "LegacyFocusStateMapper"; - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private static final boolean DEBUG = false; private final Camera mCamera; @@ -90,7 +90,7 @@ public class LegacyFocusStateMapper { final String afMode = parameters.getFocusMode(); if (!Objects.equals(mAfModePrevious, afMode)) { - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "processRequestTriggers - AF mode switched from " + mAfModePrevious + " to " + afMode); } @@ -120,7 +120,7 @@ public class LegacyFocusStateMapper { synchronized (mLock) { int latestAfRun = mAfRun; - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "onAutoFocusMoving - start " + start + " latest AF run " + latestAfRun + ", last AF run " + currentAfRun @@ -192,7 +192,7 @@ public class LegacyFocusStateMapper { mAfState = afStateAfterStart; } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "processRequestTriggers - got AF_TRIGGER_START, " + "new AF run is " + currentAfRun); } @@ -208,7 +208,7 @@ public class LegacyFocusStateMapper { synchronized (mLock) { int latestAfRun = mAfRun; - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "onAutoFocus - success " + success + " latest AF run " + latestAfRun + ", last AF run " + currentAfRun); } @@ -255,7 +255,7 @@ public class LegacyFocusStateMapper { mCamera.cancelAutoFocus(); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "processRequestTriggers - got AF_TRIGGER_CANCEL, " + "new AF run is " + updatedAfRun); } @@ -288,7 +288,7 @@ public class LegacyFocusStateMapper { newAfState = mAfState; } - if (VERBOSE && newAfState != mAfStatePrevious) { + if (DEBUG && newAfState != mAfStatePrevious) { Log.v(TAG, String.format("mapResultTriggers - afState changed from %s to %s", afStateToString(mAfStatePrevious), afStateToString(newAfState))); } diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java index 8776418..33a802b 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java @@ -55,7 +55,7 @@ import static android.hardware.camera2.legacy.ParameterUtils.*; @SuppressWarnings("deprecation") public class LegacyMetadataMapper { private static final String TAG = "LegacyMetadataMapper"; - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private static final boolean DEBUG = false; private static final long NS_PER_MS = 1000000; @@ -152,7 +152,7 @@ public class LegacyMetadataMapper { params.unflatten(parameters); mapCharacteristicsFromParameters(m, params); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "createCharacteristics metadata:"); Log.v(TAG, "--------------------------------------------------- (start)"); m.dumpToLog(); @@ -284,7 +284,7 @@ public class LegacyMetadataMapper { Camera.Size maxJpegSize = SizeAreaComparator.findLargestByArea(jpegSizes); float jpegAspectRatio = maxJpegSize.width * 1.0f / maxJpegSize.height; - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, String.format("mapScalerStreamConfigs - largest JPEG area %dx%d, AR=%f", maxJpegSize.width, maxJpegSize.height, jpegAspectRatio)); } @@ -300,7 +300,7 @@ public class LegacyMetadataMapper { PREVIEW_ASPECT_RATIO_TOLERANCE) { previewSizes.remove(index); // Assume removing from end is O(1) - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, String.format( "mapScalerStreamConfigs - removed preview size %dx%d, AR=%f " + "was not the same", @@ -329,7 +329,7 @@ public class LegacyMetadataMapper { for (int format : p.getSupportedPreviewFormats()) { if (ImageFormat.isPublicFormat(format) && format != ImageFormat.NV21) { appendStreamConfig(availableStreamConfigs, format, previewSizes); - } else if (VERBOSE) { + } else if (DEBUG) { /* * Do not add any formats unknown to us * (since it would fail runtime checks in StreamConfigurationMap) @@ -388,7 +388,7 @@ public class LegacyMetadataMapper { int j = 0; for (String mode : antiBandingModes) { int convertedMode = convertAntiBandingMode(mode); - if (VERBOSE && convertedMode == -1) { + if (DEBUG && convertedMode == -1) { Log.v(TAG, "Antibanding mode " + ((mode == null) ? "NULL" : mode) + " not supported, skipping..."); } else { @@ -525,7 +525,7 @@ public class LegacyMetadataMapper { m.set(CONTROL_AF_AVAILABLE_MODES, ArrayUtils.toIntArray(afAvail)); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "mapControlAf - control.afAvailableModes set to " + ListUtils.listToString(afAvail)); } @@ -575,7 +575,7 @@ public class LegacyMetadataMapper { m.set(CONTROL_AWB_AVAILABLE_MODES, ArrayUtils.toIntArray(awbAvail)); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "mapControlAwb - control.awbAvailableModes set to " + ListUtils.listToString(awbAvail)); } @@ -681,7 +681,7 @@ public class LegacyMetadataMapper { * We can tell if the lens is fixed focus; * but if it's not, we can't tell the minimum focus distance, so leave it null then. */ - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "mapLens - focus-mode='" + p.getFocusMode() + "'"); } @@ -691,11 +691,11 @@ public class LegacyMetadataMapper { */ m.set(LENS_INFO_MINIMUM_FOCUS_DISTANCE, LENS_INFO_MINIMUM_FOCUS_DISTANCE_FIXED_FOCUS); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "mapLens - lens.info.minimumFocusDistance = 0"); } } else { - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "mapLens - lens.info.minimumFocusDistance is unknown"); } } @@ -752,11 +752,14 @@ public class LegacyMetadataMapper { CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES , CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE , CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP , + CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE , CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES , CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS , + CameraCharacteristics.CONTROL_AVAILABLE_MODES , CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES , CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES , CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES , + CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE , CameraCharacteristics.CONTROL_MAX_REGIONS , CameraCharacteristics.FLASH_INFO_AVAILABLE , CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL , @@ -1339,7 +1342,7 @@ public class LegacyMetadataMapper { } } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "createRequestTemplate (templateId=" + templateId + ")," + " afMode=" + afMode + ", minimumFocusDistance=" + minimumFocusDistance); } diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java index 3688610..d5d7f0d 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java @@ -42,7 +42,7 @@ import static android.hardware.camera2.CaptureRequest.*; @SuppressWarnings("deprecation") public class LegacyRequestMapper { private static final String TAG = "LegacyRequestMapper"; - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private static final boolean DEBUG = false; /** Default quality for android.jpeg.quality, android.jpeg.thumbnailQuality */ private static final byte DEFAULT_JPEG_QUALITY = 85; @@ -75,7 +75,7 @@ public class LegacyRequestMapper { if (params.isZoomSupported()) { params.setZoom(zoomData.zoomIndex); - } else if (VERBOSE) { + } else if (DEBUG) { Log.v(TAG, "convertRequestToMetadata - zoom is not supported"); } } @@ -210,7 +210,7 @@ public class LegacyRequestMapper { params.setAutoExposureLock(aeLock); } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "convertRequestToMetadata - control.aeLock set to " + aeLock); } @@ -231,7 +231,7 @@ public class LegacyRequestMapper { params.setFocusMode(focusMode); } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "convertRequestToMetadata - control.afMode " + afMode + " mapped to " + focusMode); } @@ -250,7 +250,7 @@ public class LegacyRequestMapper { params.setWhiteBalance(whiteBalanceMode); } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "convertRequestToMetadata - control.awbMode " + awbMode + " mapped to " + whiteBalanceMode); } @@ -520,7 +520,7 @@ public class LegacyRequestMapper { " regions, ignoring all beyond the first " + maxNumMeteringAreas); } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "convertMeteringRegionsToLegacy - " + regionName + " areas = " + ParameterUtils.stringFromAreaList(meteringAreaList)); } @@ -593,7 +593,7 @@ public class LegacyRequestMapper { p.setFlashMode(flashModeSetting); } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "mapAeAndFlashMode - set flash.mode (api1) to " + flashModeSetting + ", requested (api2) " + flashMode diff --git a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java index bad1d28..ce85005 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java @@ -42,7 +42,7 @@ import static android.hardware.camera2.CaptureResult.*; @SuppressWarnings("deprecation") public class LegacyResultMapper { private static final String TAG = "LegacyResultMapper"; - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private static final boolean DEBUG = false; private LegacyRequest mCachedRequest = null; private CameraMetadataNative mCachedResult = null; @@ -88,7 +88,7 @@ public class LegacyResultMapper { result.set(SENSOR_TIMESTAMP, timestamp); } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "cachedConvertResultMetadata - cached? " + cached + " timestamp = " + timestamp); @@ -306,7 +306,7 @@ public class LegacyResultMapper { { boolean lock = p.isAutoExposureLockSupported() ? p.getAutoExposureLock() : false; m.set(CONTROL_AE_LOCK, lock); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "mapAe - android.control.aeLock = " + lock + ", supported = " + p.isAutoExposureLockSupported()); @@ -332,7 +332,7 @@ public class LegacyResultMapper { // control.aeRegions if (p.getMaxNumMeteringAreas() > 0) { - if (VERBOSE) { + if (DEBUG) { String meteringAreas = p.get("metering-areas"); Log.v(TAG, "mapAe - parameter dump; metering-areas: " + meteringAreas); } @@ -352,7 +352,7 @@ public class LegacyResultMapper { // control.afRegions if (p.getMaxNumFocusAreas() > 0) { - if (VERBOSE) { + if (DEBUG) { String focusAreas = p.get("focus-areas"); Log.v(TAG, "mapAe - parameter dump; focus-areas: " + focusAreas); } @@ -392,7 +392,7 @@ public class LegacyResultMapper { } } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "Metering rectangles for " + regionName + ": " + ListUtils.listToString(meteringRectList)); diff --git a/core/java/android/hardware/camera2/legacy/ParameterUtils.java b/core/java/android/hardware/camera2/legacy/ParameterUtils.java index 32bbc51..3cfd020 100644 --- a/core/java/android/hardware/camera2/legacy/ParameterUtils.java +++ b/core/java/android/hardware/camera2/legacy/ParameterUtils.java @@ -225,7 +225,7 @@ public class ParameterUtils { } private static final String TAG = "ParameterUtils"; - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private static final boolean DEBUG = false; /** getZoomRatios stores zoom ratios in 1/100 increments, e.x. a zoom of 3.2 is 320 */ private static final int ZOOM_RATIO_MULTIPLIER = 100; @@ -398,7 +398,7 @@ public class ParameterUtils { Rect cropRegionAsPreview = shrinkToSameAspectRatioCentered(previewCrop, actualCrop); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "getClosestAvailableZoomCrop - actualCrop = " + actualCrop); Log.v(TAG, "getClosestAvailableZoomCrop - previewCrop = " + previewCrop); @@ -418,7 +418,7 @@ public class ParameterUtils { List<Rect> availablePreviewCropRegions = getAvailablePreviewZoomCropRectangles(params, activeArray, streamSize); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "getClosestAvailableZoomCrop - availableReportedCropRegions = " + ListUtils.listToString(availableReportedCropRegions)); @@ -758,7 +758,7 @@ public class ParameterUtils { userCropRegion = activeArraySizeOnly; } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "convertScalerCropRegion - user crop region was " + userCropRegion); } @@ -768,7 +768,7 @@ public class ParameterUtils { previewSize, userCropRegion, /*out*/reportedCropRegion, /*out*/previewCropRegion); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "convertScalerCropRegion - zoom calculated to: " + "zoomIndex = " + zoomIdx + ", reported crop region = " + reportedCropRegion + @@ -862,7 +862,7 @@ public class ParameterUtils { reportedMetering = reportedMeteringRect.rect; } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, String.format( "convertMeteringRectangleToLegacy - activeArray = %s, meteringRect = %s, " + "previewCrop = %s, meteringArea = %s, previewMetering = %s, " + diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java index 691798f..5ea1ab8 100644 --- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java +++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java @@ -62,10 +62,9 @@ public class RequestThreadManager { private final int mCameraId; private final RequestHandlerThread mRequestThread; - private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG); + private static final boolean DEBUG = false; // For slightly more spammy messages that will get repeated every frame - private static final boolean VERBOSE = - Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.VERBOSE); + private static final boolean VERBOSE = false; private Camera mCamera; private final CameraCharacteristics mCharacteristics; diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java index 615b2c8..f928a55 100644 --- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java +++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java @@ -49,7 +49,7 @@ import java.util.List; */ public class SurfaceTextureRenderer { private static final String TAG = SurfaceTextureRenderer.class.getSimpleName(); - private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG); + private static final boolean DEBUG = false; private static final int EGL_RECORDABLE_ANDROID = 0x3142; // from EGL/eglext.h private static final int GL_MATRIX_SIZE = 16; private static final int VERTEX_POS_SIZE = 3; diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableArray.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableArray.java index d89518b..ebc74f0 100644 --- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableArray.java +++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableArray.java @@ -39,7 +39,7 @@ import java.util.ArrayList; public class MarshalQueryableArray<T> implements MarshalQueryable<T> { private static final String TAG = MarshalQueryableArray.class.getSimpleName(); - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private static final boolean DEBUG = false; private class MarshalerArray extends Marshaler<T> { private final Class<T> mClass; @@ -81,7 +81,7 @@ public class MarshalQueryableArray<T> implements MarshalQueryable<T> { + "; but there are " + (remaining % elementSize) + " left over bytes"); } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, String.format( "Attempting to unpack array (count = %d, element size = %d, bytes " + "remaining = %d) for type %s", diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableEnum.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableEnum.java index fa53db2..621a418 100644 --- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableEnum.java +++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableEnum.java @@ -38,7 +38,7 @@ import static android.hardware.camera2.marshal.MarshalHelpers.*; public class MarshalQueryableEnum<T extends Enum<T>> implements MarshalQueryable<T> { private static final String TAG = MarshalQueryableEnum.class.getSimpleName(); - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private static final boolean DEBUG = false; private static final int UINT8_MIN = 0x0; private static final int UINT8_MAX = (1 << Byte.SIZE) - 1; @@ -110,7 +110,7 @@ public class MarshalQueryableEnum<T extends Enum<T>> implements MarshalQueryable Class<?> typeClass = (Class<?>)managedType.getType(); if (typeClass.isEnum()) { - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "possible enum detected for " + typeClass); } @@ -151,7 +151,7 @@ public class MarshalQueryableEnum<T extends Enum<T>> implements MarshalQueryable "Expected values array to be the same size as the enumTypes values " + values.length + " for type " + enumType); } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "Registered enum values for type " + enumType + " values"); } diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableParcelable.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableParcelable.java index 0b7a4bf..fdde205 100644 --- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableParcelable.java +++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableParcelable.java @@ -34,7 +34,7 @@ public class MarshalQueryableParcelable<T extends Parcelable> implements MarshalQueryable<T> { private static final String TAG = "MarshalParcelable"; - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private static final boolean DEBUG = false; private static final String FIELD_CREATOR = "CREATOR"; @@ -70,7 +70,7 @@ public class MarshalQueryableParcelable<T extends Parcelable> @Override public void marshal(T value, ByteBuffer buffer) { - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "marshal " + value); } @@ -100,7 +100,7 @@ public class MarshalQueryableParcelable<T extends Parcelable> @Override public T unmarshal(ByteBuffer buffer) { - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "unmarshal, buffer remaining " + buffer.remaining()); } @@ -142,7 +142,7 @@ public class MarshalQueryableParcelable<T extends Parcelable> buffer.reset(); buffer.position(buffer.position() + actualLength); - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "unmarshal, parcel length was " + actualLength); Log.v(TAG, "unmarshal, value is " + value); } @@ -165,7 +165,7 @@ public class MarshalQueryableParcelable<T extends Parcelable> value.writeToParcel(parcel, /*flags*/0); int length = parcel.marshall().length; - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "calculateMarshalSize, length when parceling " + value + " is " + length); } diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableString.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableString.java index bf518bb..d2c3908 100644 --- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableString.java +++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableString.java @@ -31,7 +31,7 @@ import static android.hardware.camera2.impl.CameraMetadataNative.*; public class MarshalQueryableString implements MarshalQueryable<String> { private static final String TAG = MarshalQueryableString.class.getSimpleName(); - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private static final boolean DEBUG = false; private static final Charset UTF8_CHARSET = Charset.forName("UTF-8"); private static final byte NUL = (byte)'\0'; // used as string terminator @@ -72,7 +72,7 @@ public class MarshalQueryableString implements MarshalQueryable<String> { stringLength++; } - if (VERBOSE) { + if (DEBUG) { Log.v(TAG, "unmarshal - scanned " + stringLength + " characters; found null? " + foundNull); diff --git a/core/java/android/hardware/camera2/utils/ArrayUtils.java b/core/java/android/hardware/camera2/utils/ArrayUtils.java index 79a335c..99ddf6e 100644 --- a/core/java/android/hardware/camera2/utils/ArrayUtils.java +++ b/core/java/android/hardware/camera2/utils/ArrayUtils.java @@ -28,7 +28,7 @@ import java.util.Objects; public class ArrayUtils { private static final String TAG = "ArrayUtils"; - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private static final boolean DEBUG = false; /** Return the index of {@code needle} in the {@code array}, or else {@code -1} */ public static <T> int getArrayIndex(T[] array, T needle) { @@ -117,7 +117,7 @@ public class ArrayUtils { // Guard against unexpected values if (strIndex < 0) { - if (VERBOSE) Log.v(TAG, "Ignoring invalid value " + str); + if (DEBUG) Log.v(TAG, "Ignoring invalid value " + str); continue; } diff --git a/core/java/android/hardware/camera2/utils/TaskDrainer.java b/core/java/android/hardware/camera2/utils/TaskDrainer.java index dc09f62..7c46e50 100644 --- a/core/java/android/hardware/camera2/utils/TaskDrainer.java +++ b/core/java/android/hardware/camera2/utils/TaskDrainer.java @@ -52,7 +52,7 @@ public class TaskDrainer<T> { } private static final String TAG = "TaskDrainer"; - private final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + private final boolean DEBUG = false; private final Handler mHandler; private final DrainListener mListener; @@ -110,7 +110,7 @@ public class TaskDrainer<T> { */ public void taskStarted(T task) { synchronized (mLock) { - if (VERBOSE) { + if (DEBUG) { Log.v(TAG + "[" + mName + "]", "taskStarted " + task); } @@ -141,7 +141,7 @@ public class TaskDrainer<T> { */ public void taskFinished(T task) { synchronized (mLock) { - if (VERBOSE) { + if (DEBUG) { Log.v(TAG + "[" + mName + "]", "taskFinished " + task); } @@ -163,7 +163,7 @@ public class TaskDrainer<T> { public void beginDrain() { synchronized (mLock) { if (!mDraining) { - if (VERBOSE) { + if (DEBUG) { Log.v(TAG + "[" + mName + "]", "beginDrain started"); } @@ -172,7 +172,7 @@ public class TaskDrainer<T> { // If all tasks that had started had already finished by now, fire #onDrained checkIfDrainFinished(); } else { - if (VERBOSE) { + if (DEBUG) { Log.v(TAG + "[" + mName + "]", "beginDrain ignored"); } } @@ -190,7 +190,7 @@ public class TaskDrainer<T> { mHandler.post(new Runnable() { @Override public void run() { - if (VERBOSE) { + if (DEBUG) { Log.v(TAG + "[" + mName + "]", "onDrained"); } diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 1b57055..81a65f8 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -306,6 +306,14 @@ public class InputMethodService extends AbstractInputMethodService { int mStatusIcon; int mBackDisposition; + /** + * {@code true} when the previous IME had non-empty inset at the bottom of the screen and we + * have not shown our own window yet. In this situation, the previous inset continues to be + * shown as an empty region until it is explicitly updated. Basically we can trigger the update + * by calling 1) {@code mWindow.show()} or 2) {@link #clearInsetOfPreviousIme()}. + */ + boolean mShouldClearInsetOfPreviousIme; + final Insets mTmpInsets = new Insets(); final int[] mTmpLocation = new int[2]; @@ -408,6 +416,7 @@ public class InputMethodService extends AbstractInputMethodService { mShowInputRequested = false; mShowInputForced = false; doHideWindow(); + clearInsetOfPreviousIme(); if (resultReceiver != null) { resultReceiver.send(wasVis != isInputViewShown() ? InputMethodManager.RESULT_HIDDEN @@ -432,6 +441,7 @@ public class InputMethodService extends AbstractInputMethodService { mWindowAdded = false; } } + clearInsetOfPreviousIme(); // If user uses hard keyboard, IME button should always be shown. boolean showing = isInputViewShown(); mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0), @@ -669,6 +679,9 @@ public class InputMethodService extends AbstractInputMethodService { super.setTheme(mTheme); super.onCreate(); mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); + // If the previous IME has occupied non-empty inset in the screen, we need to decide whether + // we continue to use the same size of the inset or update it + mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0); mInflater = (LayoutInflater)getSystemService( Context.LAYOUT_INFLATER_SERVICE); mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState, @@ -1494,6 +1507,9 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) Log.v(TAG, "showWindow: showing!"); onWindowShown(); mWindow.show(); + // Put here rather than in onWindowShown() in case people forget to call + // super.onWindowShown(). + mShouldClearInsetOfPreviousIme = false; } } @@ -1540,7 +1556,23 @@ public class InputMethodService extends AbstractInputMethodService { public void onWindowHidden() { // Intentionally empty } - + + /** + * Reset the inset occupied the previous IME when and only when + * {@link #mShouldClearInsetOfPreviousIme} is {@code true}. + */ + private void clearInsetOfPreviousIme() { + if (DEBUG) Log.v(TAG, "clearInsetOfPreviousIme() " + + " mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme); + if (!mShouldClearInsetOfPreviousIme || mWindow == null) return; + // We do not call onWindowShown() and onWindowHidden() so as not to make the IME author + // confused. + // TODO: Find out a better way which has less side-effect. + mWindow.show(); + mWindow.hide(); + mShouldClearInsetOfPreviousIme = false; + } + /** * Called when a new client has bound to the input method. This * may be followed by a series of {@link #onStartInput(EditorInfo, boolean)} @@ -2428,5 +2460,6 @@ public class InputMethodService extends AbstractInputMethodService { + " visibleTopInsets=" + mTmpInsets.visibleTopInsets + " touchableInsets=" + mTmpInsets.touchableInsets + " touchableRegion=" + mTmpInsets.touchableRegion); + p.println(" mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme); } } diff --git a/core/java/android/net/IpReachabilityMonitor.java b/core/java/android/net/IpReachabilityMonitor.java index 78d147d..3cfd8b2 100644 --- a/core/java/android/net/IpReachabilityMonitor.java +++ b/core/java/android/net/IpReachabilityMonitor.java @@ -443,14 +443,13 @@ public class IpReachabilityMonitor { if (mIpWatchList.containsKey(destination)) { final short value = (msgType == NetlinkConstants.RTM_DELNEIGH) - ? StructNdMsg.NUD_FAILED + ? StructNdMsg.NUD_NONE : nudState; mIpWatchList.put(destination, value); } } - if ((msgType == NetlinkConstants.RTM_DELNEIGH) || - (nudState == StructNdMsg.NUD_FAILED)) { + if (nudState == StructNdMsg.NUD_FAILED) { Log.w(TAG, "ALERT: " + eventMsg); handleNeighborLost(eventMsg); } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 5f515eb..0a45b8b 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -132,6 +132,16 @@ public abstract class BatteryStats implements Parcelable { public static final int AUDIO_TURNED_ON = 15; /** + * A constant indicating a flashlight turn on timer + */ + public static final int FLASHLIGHT_TURNED_ON = 16; + + /** + * A constant indicating a camera turn on timer + */ + public static final int CAMERA_TURNED_ON = 17; + + /** * Include all of the data in the stats, including previously saved data. */ public static final int STATS_SINCE_CHARGED = 0; @@ -208,6 +218,10 @@ public abstract class BatteryStats implements Parcelable { private static final String CHARGE_STEP_DATA = "csd"; private static final String DISCHARGE_TIME_REMAIN_DATA = "dtr"; private static final String CHARGE_TIME_REMAIN_DATA = "ctr"; + private static final String FLASHLIGHT_DATA = "fla"; + private static final String CAMERA_DATA = "cam"; + private static final String VIDEO_DATA = "vid"; + private static final String AUDIO_DATA = "aud"; private final StringBuilder mFormatBuilder = new StringBuilder(32); private final Formatter mFormatter = new Formatter(mFormatBuilder); @@ -381,8 +395,10 @@ public abstract class BatteryStats implements Parcelable { public abstract long getWifiBatchedScanTime(int csphBin, long elapsedRealtimeUs, int which); public abstract int getWifiBatchedScanCount(int csphBin, int which); public abstract long getWifiMulticastTime(long elapsedRealtimeUs, int which); - public abstract long getAudioTurnedOnTime(long elapsedRealtimeUs, int which); - public abstract long getVideoTurnedOnTime(long elapsedRealtimeUs, int which); + public abstract Timer getAudioTurnedOnTimer(); + public abstract Timer getVideoTurnedOnTimer(); + public abstract Timer getFlashlightTurnedOnTimer(); + public abstract Timer getCameraTurnedOnTimer(); public abstract Timer getForegroundActivityTimer(); // Time this uid has any processes in foreground state. @@ -1106,6 +1122,7 @@ public abstract class BatteryStats implements Parcelable { public static final int STATE2_CHARGING_FLAG = 1<<25; public static final int STATE2_PHONE_IN_CALL_FLAG = 1<<24; public static final int STATE2_BLUETOOTH_ON_FLAG = 1<<23; + public static final int STATE2_CAMERA_FLAG = 1<<22; public static final int MOST_INTERESTING_STATES2 = STATE2_POWER_SAVE_FLAG | STATE2_WIFI_ON_FLAG | STATE2_DEVICE_IDLE_FLAG @@ -1813,6 +1830,7 @@ public abstract class BatteryStats implements Parcelable { new BitDescription(HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK, HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT, "wifi_suppl", "Wsp", WIFI_SUPPL_STATE_NAMES, WIFI_SUPPL_STATE_SHORT_NAMES), + new BitDescription(HistoryItem.STATE2_CAMERA_FLAG, "camera", "ca"), }; public static final String[] HISTORY_EVENT_NAMES = new String[] { @@ -2317,10 +2335,10 @@ public abstract class BatteryStats implements Parcelable { */ private static final String printWakeLock(StringBuilder sb, Timer timer, long elapsedRealtimeUs, String name, int which, String linePrefix) { - + if (timer != null) { long totalTimeMillis = computeWakeLock(timer, elapsedRealtimeUs, which); - + int count = timer.getCountLocked(which); if (totalTimeMillis != 0) { sb.append(linePrefix); @@ -2337,6 +2355,40 @@ public abstract class BatteryStats implements Parcelable { } return linePrefix; } + + /** + * + * @param pw a PrintWriter object to print to. + * @param sb a StringBuilder object. + * @param timer a Timer object contining the wakelock times. + * @param rawRealtime the current on-battery time in microseconds. + * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. + * @param prefix a String to be prepended to each line of output. + * @param type the name of the timer. + */ + private static final boolean printTimer(PrintWriter pw, StringBuilder sb, Timer timer, + long rawRealtime, int which, String prefix, String type) { + if (timer != null) { + // Convert from microseconds to milliseconds with rounding + final long totalTime = (timer.getTotalTimeLocked( + rawRealtime, which) + 500) / 1000; + final int count = timer.getCountLocked(which); + if (totalTime != 0) { + sb.setLength(0); + sb.append(prefix); + sb.append(" "); + sb.append(type); + sb.append(": "); + formatTimeMs(sb, totalTime); + sb.append("realtime ("); + sb.append(count); + sb.append(" times)"); + pw.println(sb.toString()); + return true; + } + } + return false; + } /** * Checkin version of wakelock printer. Prints simple comma-separated list. @@ -2375,12 +2427,15 @@ public abstract class BatteryStats implements Parcelable { */ private static final void dumpLine(PrintWriter pw, int uid, String category, String type, Object... args ) { - pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); - pw.print(uid); pw.print(','); - pw.print(category); pw.print(','); + pw.print(BATTERY_STATS_CHECKIN_VERSION); + pw.print(','); + pw.print(uid); + pw.print(','); + pw.print(category); + pw.print(','); pw.print(type); - - for (Object arg : args) { + + for (Object arg : args) { pw.print(','); pw.print(arg); } @@ -2388,6 +2443,30 @@ public abstract class BatteryStats implements Parcelable { } /** + * Dump a given timer stat for terse checkin mode. + * + * @param pw the PageWriter to dump log to + * @param uid the UID to log + * @param category category of data (e.g. "total", "last", "unplugged", "current" ) + * @param type type of data (e.g. "wakelock", "sensor", "process", "apk" , "process", "network") + * @param timer a {@link Timer} to dump stats for + * @param rawRealtime the current elapsed realtime of the system in microseconds + * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT + */ + private static final void dumpTimer(PrintWriter pw, int uid, String category, String type, + Timer timer, long rawRealtime, int which) { + if (timer != null) { + // Convert from microseconds to milliseconds with rounding + final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) + / 1000; + final int count = timer.getCountLocked(which); + if (totalTime != 0) { + dumpLine(pw, uid, category, type, totalTime, count); + } + } + } + + /** * Temporary for settings. */ public final void dumpCheckinLocked(Context context, PrintWriter pw, int which, int reqUid) { @@ -2764,6 +2843,15 @@ public abstract class BatteryStats implements Parcelable { } } + dumpTimer(pw, uid, category, FLASHLIGHT_DATA, u.getFlashlightTurnedOnTimer(), + rawRealtime, which); + dumpTimer(pw, uid, category, CAMERA_DATA, u.getCameraTurnedOnTimer(), + rawRealtime, which); + dumpTimer(pw, uid, category, VIDEO_DATA, u.getVideoTurnedOnTimer(), + rawRealtime, which); + dumpTimer(pw, uid, category, AUDIO_DATA, u.getAudioTurnedOnTimer(), + rawRealtime, which); + final SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats(); final int NSE = sensors.size(); for (int ise=0; ise<NSE; ise++) { @@ -2781,27 +2869,11 @@ public abstract class BatteryStats implements Parcelable { } } - final Timer vibTimer = u.getVibratorOnTimer(); - if (vibTimer != null) { - // Convert from microseconds to milliseconds with rounding - final long totalTime = (vibTimer.getTotalTimeLocked(rawRealtime, which) + 500) - / 1000; - final int count = vibTimer.getCountLocked(which); - if (totalTime != 0) { - dumpLine(pw, uid, category, VIBRATOR_DATA, totalTime, count); - } - } + dumpTimer(pw, uid, category, VIBRATOR_DATA, u.getVibratorOnTimer(), + rawRealtime, which); - final Timer fgTimer = u.getForegroundActivityTimer(); - if (fgTimer != null) { - // Convert from microseconds to milliseconds with rounding - final long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500) - / 1000; - final int count = fgTimer.getCountLocked(which); - if (totalTime != 0) { - dumpLine(pw, uid, category, FOREGROUND_DATA, totalTime, count); - } - } + dumpTimer(pw, uid, category, FOREGROUND_DATA, u.getForegroundActivityTimer(), + rawRealtime, which); final Object[] stateTimes = new Object[Uid.NUM_PROCESS_STATE]; long totalStateTime = 0; @@ -3282,12 +3354,13 @@ public abstract class BatteryStats implements Parcelable { final long wifiIdleTimeMs = getWifiControllerActivity(CONTROLLER_IDLE_TIME, which); final long wifiRxTimeMs = getWifiControllerActivity(CONTROLLER_RX_TIME, which); final long wifiTxTimeMs = getWifiControllerActivity(CONTROLLER_TX_TIME, which); + final long wifiPowerDrainMaMs = getWifiControllerActivity(CONTROLLER_POWER_DRAIN, which); final long wifiTotalTimeMs = wifiIdleTimeMs + wifiRxTimeMs + wifiTxTimeMs; sb.setLength(0); sb.append(prefix); sb.append(" WiFi Idle time: "); formatTimeMs(sb, wifiIdleTimeMs); - sb.append(" ("); + sb.append("("); sb.append(formatRatioLocked(wifiIdleTimeMs, wifiTotalTimeMs)); sb.append(")"); pw.println(sb.toString()); @@ -3295,7 +3368,7 @@ public abstract class BatteryStats implements Parcelable { sb.setLength(0); sb.append(prefix); sb.append(" WiFi Rx time: "); formatTimeMs(sb, wifiRxTimeMs); - sb.append(" ("); + sb.append("("); sb.append(formatRatioLocked(wifiRxTimeMs, wifiTotalTimeMs)); sb.append(")"); pw.println(sb.toString()); @@ -3303,16 +3376,16 @@ public abstract class BatteryStats implements Parcelable { sb.setLength(0); sb.append(prefix); sb.append(" WiFi Tx time: "); formatTimeMs(sb, wifiTxTimeMs); - sb.append(" ("); + sb.append("("); sb.append(formatRatioLocked(wifiTxTimeMs, wifiTotalTimeMs)); sb.append(")"); pw.println(sb.toString()); sb.setLength(0); sb.append(prefix); - sb.append(" WiFi Power drain: ").append(BatteryStatsHelper.makemAh( - getWifiControllerActivity(CONTROLLER_POWER_DRAIN, which) / (double)(1000*60*60))); - sb.append(" mAh"); + sb.append(" WiFi Power drain: ").append( + BatteryStatsHelper.makemAh(wifiPowerDrainMaMs / (double) (1000*60*60))); + sb.append("mAh"); pw.println(sb.toString()); final long bluetoothIdleTimeMs = @@ -3325,7 +3398,7 @@ public abstract class BatteryStats implements Parcelable { sb.setLength(0); sb.append(prefix); sb.append(" Bluetooth Idle time: "); formatTimeMs(sb, bluetoothIdleTimeMs); - sb.append(" ("); + sb.append("("); sb.append(formatRatioLocked(bluetoothIdleTimeMs, bluetoothTotalTimeMs)); sb.append(")"); pw.println(sb.toString()); @@ -3333,7 +3406,7 @@ public abstract class BatteryStats implements Parcelable { sb.setLength(0); sb.append(prefix); sb.append(" Bluetooth Rx time: "); formatTimeMs(sb, bluetoothRxTimeMs); - sb.append(" ("); + sb.append("("); sb.append(formatRatioLocked(bluetoothRxTimeMs, bluetoothTotalTimeMs)); sb.append(")"); pw.println(sb.toString()); @@ -3341,7 +3414,7 @@ public abstract class BatteryStats implements Parcelable { sb.setLength(0); sb.append(prefix); sb.append(" Bluetooth Tx time: "); formatTimeMs(sb, bluetoothTxTimeMs); - sb.append(" ("); + sb.append("("); sb.append(formatRatioLocked(bluetoothTxTimeMs, bluetoothTotalTimeMs)); sb.append(")"); pw.println(sb.toString()); @@ -3351,7 +3424,7 @@ public abstract class BatteryStats implements Parcelable { sb.append(" Bluetooth Power drain: ").append(BatteryStatsHelper.makemAh( getBluetoothControllerActivity(CONTROLLER_POWER_DRAIN, which) / (double)(1000*60*60))); - sb.append(" mAh"); + sb.append("mAh"); pw.println(sb.toString()); pw.println(); @@ -3656,6 +3729,27 @@ public abstract class BatteryStats implements Parcelable { pw.println(sb.toString()); } + final long uidWifiIdleTimeMs = u.getWifiControllerActivity(CONTROLLER_IDLE_TIME, which); + final long uidWifiRxTimeMs = u.getWifiControllerActivity(CONTROLLER_RX_TIME, which); + final long uidWifiTxTimeMs = u.getWifiControllerActivity(CONTROLLER_TX_TIME, which); + final long uidWifiTotalTimeMs = uidWifiIdleTimeMs + uidWifiRxTimeMs + uidWifiTxTimeMs; + if (uidWifiTotalTimeMs > 0) { + sb.setLength(0); + sb.append(prefix).append(" WiFi Idle time: "); + formatTimeMs(sb, uidWifiIdleTimeMs); + sb.append("(").append(formatRatioLocked(uidWifiIdleTimeMs, uidWifiTotalTimeMs)) + .append(")\n"); + + sb.append(prefix).append(" WiFi Rx time: "); formatTimeMs(sb, uidWifiRxTimeMs); + sb.append("(").append(formatRatioLocked(uidWifiRxTimeMs, uidWifiTotalTimeMs)) + .append(")\n"); + + sb.append(prefix).append(" WiFi Tx time: "); formatTimeMs(sb, uidWifiTxTimeMs); + sb.append("(").append(formatRatioLocked(uidWifiTxTimeMs, uidWifiTotalTimeMs)) + .append(")"); + pw.println(sb.toString()); + } + if (u.hasUserActivity()) { boolean hasData = false; for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) { @@ -3788,6 +3882,15 @@ public abstract class BatteryStats implements Parcelable { uidActivity = true; } + uidActivity |= printTimer(pw, sb, u.getFlashlightTurnedOnTimer(), rawRealtime, which, + prefix, "Flashlight"); + uidActivity |= printTimer(pw, sb, u.getCameraTurnedOnTimer(), rawRealtime, which, + prefix, "Camera"); + uidActivity |= printTimer(pw, sb, u.getVideoTurnedOnTimer(), rawRealtime, which, + prefix, "Video"); + uidActivity |= printTimer(pw, sb, u.getAudioTurnedOnTimer(), rawRealtime, which, + prefix, "Audio"); + final SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats(); final int NSE = sensors.size(); for (int ise=0; ise<NSE; ise++) { @@ -3827,44 +3930,10 @@ public abstract class BatteryStats implements Parcelable { uidActivity = true; } - final Timer vibTimer = u.getVibratorOnTimer(); - if (vibTimer != null) { - // Convert from microseconds to milliseconds with rounding - final long totalTime = (vibTimer.getTotalTimeLocked( - rawRealtime, which) + 500) / 1000; - final int count = vibTimer.getCountLocked(which); - //timer.logState(); - if (totalTime != 0) { - sb.setLength(0); - sb.append(prefix); - sb.append(" Vibrator: "); - formatTimeMs(sb, totalTime); - sb.append("realtime ("); - sb.append(count); - sb.append(" times)"); - pw.println(sb.toString()); - uidActivity = true; - } - } - - final Timer fgTimer = u.getForegroundActivityTimer(); - if (fgTimer != null) { - // Convert from microseconds to milliseconds with rounding - final long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500) - / 1000; - final int count = fgTimer.getCountLocked(which); - if (totalTime != 0) { - sb.setLength(0); - sb.append(prefix); - sb.append(" Foreground activities: "); - formatTimeMs(sb, totalTime); - sb.append("realtime ("); - sb.append(count); - sb.append(" times)"); - pw.println(sb.toString()); - uidActivity = true; - } - } + uidActivity |= printTimer(pw, sb, u.getVibratorOnTimer(), rawRealtime, which, prefix, + "Vibrator"); + uidActivity |= printTimer(pw, sb, u.getForegroundActivityTimer(), rawRealtime, which, + prefix, "Foreground activities"); long totalStateTime = 0; for (int ips=0; ips<Uid.NUM_PROCESS_STATE; ips++) { diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl index 602bfea..268295d 100644 --- a/core/java/android/os/IDeviceIdleController.aidl +++ b/core/java/android/os/IDeviceIdleController.aidl @@ -16,6 +16,8 @@ package android.os; +import android.os.UserHandle; + /** @hide */ interface IDeviceIdleController { void addPowerSaveWhitelistApp(String name); @@ -23,5 +25,7 @@ interface IDeviceIdleController { String[] getSystemPowerWhitelist(); String[] getFullPowerWhitelist(); int[] getAppIdWhitelist(); + int[] getAppIdTempWhitelist(); boolean isPowerSaveWhitelistApp(String name); + void addPowerSaveTempWhitelistApp(String name, long duration, int userId); } diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 1d9d7d2..8b18f32 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -928,6 +928,14 @@ public final class PowerManager { = "android.os.action.POWER_SAVE_WHITELIST_CHANGED"; /** + * @hide Intent that is broadcast when the set of temporarily whitelisted apps has changed. + * This broadcast is only sent to registered receivers. + */ + @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED + = "android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED"; + + /** * Intent that is broadcast when the state of {@link #isPowerSaveMode()} is about to change. * This broadcast is only sent to registered receivers. * diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java index e523285..e742f98 100644 --- a/core/java/android/os/PowerManagerInternal.java +++ b/core/java/android/os/PowerManagerInternal.java @@ -137,6 +137,8 @@ public abstract class PowerManagerInternal { public abstract void setDeviceIdleWhitelist(int[] appids); + public abstract void setDeviceIdleTempWhitelist(int[] appids); + public abstract void updateUidProcState(int uid, int procState); public abstract void uidGone(int uid); diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index 4aeab49..0c79094 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -71,6 +71,7 @@ public class RecoverySystem { /** Used to communicate with recovery. See bootable/recovery/recovery.c. */ private static File RECOVERY_DIR = new File("/cache/recovery"); private static File COMMAND_FILE = new File(RECOVERY_DIR, "command"); + private static File UNCRYPT_FILE = new File(RECOVERY_DIR, "uncrypt_file"); private static File LOG_FILE = new File(RECOVERY_DIR, "log"); private static String LAST_PREFIX = "last_"; @@ -333,8 +334,21 @@ public class RecoverySystem { public static void installPackage(Context context, File packageFile) throws IOException { String filename = packageFile.getCanonicalPath(); + + FileWriter uncryptFile = new FileWriter(UNCRYPT_FILE); + try { + uncryptFile.write(filename + "\n"); + } finally { + uncryptFile.close(); + } Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!"); + // If the package is on the /data partition, write the block map file + // into COMMAND_FILE instead. + if (filename.startsWith("/data/")) { + filename = "@/cache/recovery/block.map"; + } + final String filenameArg = "--update_package=" + filename; final String localeArg = "--locale=" + Locale.getDefault().toString(); bootCommand(context, filenameArg, localeArg); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index a81b83f..ef7e747 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -200,6 +200,20 @@ public class UserManager { public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering"; /** + * Specifies if a user is disallowed from resetting network settings + * from Settings. This can only be set by device owners and profile owners on the primary user. + * The default value is <code>false</code>. + * <p/>This restriction has no effect on secondary users and managed profiles since only the + * primary user can reset the network settings of the device. + * + * <p/>Key for user restrictions. + * <p/>Type: Boolean + * @see #setUserRestrictions(Bundle) + * @see #getUserRestrictions() + */ + public static final String DISALLOW_NETWORK_RESET = "no_network_reset"; + + /** * Specifies if a user is disallowed from factory resetting * from Settings. This can only be set by device owners and profile owners on the primary user. * The default value is <code>false</code>. diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java index c6ea50a..e1b5a6d 100644 --- a/core/java/android/provider/VoicemailContract.java +++ b/core/java/android/provider/VoicemailContract.java @@ -19,6 +19,7 @@ package android.provider; import android.Manifest; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; @@ -27,6 +28,7 @@ import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.provider.CallLog.Calls; +import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.Voicemail; @@ -211,13 +213,17 @@ public class VoicemailContract { // that was encoded into call log databases. /** - * The component name of the account in string form. + * The {@link ComponentName} of the {@link PhoneAccount} in string form. The + * {@link PhoneAccount} of the voicemail is used to differentiate voicemails from different + * sources. * <P>Type: TEXT</P> */ public static final String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name"; /** - * The identifier of a account that is unique to a specified component. + * The identifier of a {@link PhoneAccount} that is unique to a specified + * {@link ComponentName}. The {@link PhoneAccount} of the voicemail is used to differentiate + * voicemails from different sources. * <P>Type: TEXT</P> */ public static final String PHONE_ACCOUNT_ID = "subscription_id"; @@ -340,13 +346,15 @@ public class VoicemailContract { // PHONE_ACCOUNT_* fields. /** - * The component name of the account in string form. + * The {@link ComponentName} of the {@link PhoneAccount} in string form. The + * {@link PhoneAccount} differentiates voicemail sources from the same package. * <P>Type: TEXT</P> */ public static final String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name"; /** - * The identifier of a account that is unique to a specified component. + * The identifier of a {@link PhoneAccount} that is unique to a specified component. The + * {@link PhoneAccount} differentiates voicemail sources from the same package. * <P>Type: TEXT</P> */ public static final String PHONE_ACCOUNT_ID = "phone_account_id"; diff --git a/core/java/android/service/carrier/CarrierConfigService.java b/core/java/android/service/carrier/CarrierService.java index bf33ad5..15ccc25 100644 --- a/core/java/android/service/carrier/CarrierConfigService.java +++ b/core/java/android/service/carrier/CarrierService.java @@ -20,31 +20,35 @@ import android.os.IBinder; import android.os.PersistableBundle; /** - * A service that sets carrier configuration for telephony services. + * A service that exposes carrier-specific functionality to the system. * <p> * To extend this class, you must declare the service in your manifest file to require the * {@link android.Manifest.permission#BIND_CARRIER_SERVICES} permission and include an intent - * filter with the {@link #SERVICE_INTERFACE} action. For example: + * filter with the {@link #CONFIG_SERVICE_INTERFACE} action if the service exposes carrier config + * and the {@link #BIND_SERVICE_INTERFACE} action if the service should have a long-lived binding. + * For example: * </p> * * <pre>{@code - * <service android:name=".MyCarrierConfigService" + * <service android:name=".MyCarrierService" * android:label="@string/service_name" * android:permission="android.permission.BIND_CARRIER_SERVICES"> * <intent-filter> - * <action android:name="android.service.carrier.CarrierConfigService" /> + * <action android:name="android.service.carrier.ConfigService" /> + * <action android:name="android.service.carrier.BindService" /> * </intent-filter> * </service> * }</pre> */ -public abstract class CarrierConfigService extends Service { +public abstract class CarrierService extends Service { - public static final String SERVICE_INTERFACE = "android.service.carrier.CarrierConfigService"; + public static final String CONFIG_SERVICE_INTERFACE = "android.service.carrier.ConfigService"; + public static final String BIND_SERVICE_INTERFACE = "android.service.carrier.BindService"; - private final ICarrierConfigService.Stub mStubWrapper; + private final ICarrierService.Stub mStubWrapper; - public CarrierConfigService() { - mStubWrapper = new ICarrierConfigServiceWrapper(); + public CarrierService() { + mStubWrapper = new ICarrierServiceWrapper(); } /** @@ -82,23 +86,24 @@ public abstract class CarrierConfigService extends Service { /** @hide */ @Override public final IBinder onBind(Intent intent) { - if (!SERVICE_INTERFACE.equals(intent.getAction())) { + if (!CONFIG_SERVICE_INTERFACE.equals(intent.getAction()) + || !BIND_SERVICE_INTERFACE.equals(intent.getAction())) { return null; } return mStubWrapper; } /** - * A wrapper around ICarrierConfigService that forwards calls to implementations of - * {@link CarrierConfigService}. + * A wrapper around ICarrierService that forwards calls to implementations of + * {@link CarrierService}. * * @hide */ - private class ICarrierConfigServiceWrapper extends ICarrierConfigService.Stub { + private class ICarrierServiceWrapper extends ICarrierService.Stub { @Override public PersistableBundle getCarrierConfig(CarrierIdentifier id) { - return CarrierConfigService.this.onLoadConfig(id); + return CarrierService.this.onLoadConfig(id); } } } diff --git a/core/java/android/service/carrier/ICarrierConfigService.aidl b/core/java/android/service/carrier/ICarrierService.aidl index abbc000..4c87585 100644 --- a/core/java/android/service/carrier/ICarrierConfigService.aidl +++ b/core/java/android/service/carrier/ICarrierService.aidl @@ -20,13 +20,13 @@ import android.os.PersistableBundle; import android.service.carrier.CarrierIdentifier; /** - * Service used to get carrier config from carrier apps. + * Service used to expose carrier-specific functionality to the system. * - * @see android.service.carrier.CarrierConfigService + * @see android.service.carrier.CarrierService * @hide */ -interface ICarrierConfigService { +interface ICarrierService { - /** @see android.service.carrier.CarrierConfigService#onLoadConfig */ + /** @see android.service.carrier.CarrierService#onLoadConfig */ PersistableBundle getCarrierConfig(in CarrierIdentifier id); } diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.aidl b/core/java/android/service/gatekeeper/GateKeeperResponse.aidl new file mode 100644 index 0000000..966606e --- /dev/null +++ b/core/java/android/service/gatekeeper/GateKeeperResponse.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.gatekeeper; + +/** + * Response object for a GateKeeper verification request. + * @hide + */ +parcelable GateKeeperResponse; + diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.java b/core/java/android/service/gatekeeper/GateKeeperResponse.java new file mode 100644 index 0000000..a512957 --- /dev/null +++ b/core/java/android/service/gatekeeper/GateKeeperResponse.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.gatekeeper; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Response object for a GateKeeper verification request. + * @hide + */ +public final class GateKeeperResponse implements Parcelable { + + public static final int RESPONSE_ERROR = -1; + public static final int RESPONSE_OK = 0; + public static final int RESPONSE_RETRY = 1; + + private final int mResponseCode; + + private int mTimeout; + private byte[] mPayload; + private boolean mShouldReEnroll; + + private GateKeeperResponse(int responseCode) { + mResponseCode = responseCode; + } + + private GateKeeperResponse(int responseCode, int timeout) { + mResponseCode = responseCode; + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<GateKeeperResponse> CREATOR + = new Parcelable.Creator<GateKeeperResponse>() { + @Override + public GateKeeperResponse createFromParcel(Parcel source) { + int responseCode = source.readInt(); + GateKeeperResponse response = new GateKeeperResponse(responseCode); + if (responseCode == RESPONSE_RETRY) { + response.setTimeout(source.readInt()); + } else if (responseCode == RESPONSE_OK) { + response.setShouldReEnroll(source.readInt() == 1); + int size = source.readInt(); + if (size > 0) { + byte[] payload = new byte[size]; + source.readByteArray(payload); + response.setPayload(payload); + } + } + return response; + } + + @Override + public GateKeeperResponse[] newArray(int size) { + return new GateKeeperResponse[size]; + } + + }; + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mResponseCode); + if (mResponseCode == RESPONSE_RETRY) { + dest.writeInt(mTimeout); + } else if (mResponseCode == RESPONSE_OK) { + dest.writeInt(mShouldReEnroll ? 1 : 0); + if (mPayload != null) { + dest.writeInt(mPayload.length); + dest.writeByteArray(mPayload); + } + } + } + + public byte[] getPayload() { + return mPayload; + } + + public int getTimeout() { + return mTimeout; + } + + public boolean getShouldReEnroll() { + return mShouldReEnroll; + } + + public int getResponseCode() { + return mResponseCode; + } + + private void setTimeout(int timeout) { + mTimeout = timeout; + } + + private void setShouldReEnroll(boolean shouldReEnroll) { + mShouldReEnroll = shouldReEnroll; + } + + private void setPayload(byte[] payload) { + mPayload = payload; + } + +} diff --git a/core/java/android/service/gatekeeper/IGateKeeperService.aidl b/core/java/android/service/gatekeeper/IGateKeeperService.aidl index 4f46701..6db2110 100644 --- a/core/java/android/service/gatekeeper/IGateKeeperService.aidl +++ b/core/java/android/service/gatekeeper/IGateKeeperService.aidl @@ -16,6 +16,8 @@ package android.service.gatekeeper; +import android.service.gatekeeper.GateKeeperResponse; + /** * Interface for communication with GateKeeper, the * secure password storage daemon. @@ -34,9 +36,9 @@ interface IGateKeeperService { * If provided, must verify against the currentPasswordHandle. * @param desiredPassword The new desired password, for which a handle will be returned * upon success. - * @return the handle corresponding to desiredPassword, or null + * @return an EnrollResponse or null on failure */ - byte[] enroll(int uid, in byte[] currentPasswordHandle, in byte[] currentPassword, + GateKeeperResponse enroll(int uid, in byte[] currentPasswordHandle, in byte[] currentPassword, in byte[] desiredPassword); /** @@ -45,10 +47,10 @@ interface IGateKeeperService { * @param enrolledPasswordHandle The handle against which the provided password will be * verified. * @param The plaintext blob to verify against enrolledPassword. - * @return True if the authentication was successful + * @return a VerifyResponse, or null on failure. */ - boolean verify(int uid, in byte[] enrolledPasswordHandle, - in byte[] providedPassword); + GateKeeperResponse verify(int uid, in byte[] enrolledPasswordHandle, in byte[] providedPassword); + /** * Verifies an enrolled handle against a provided, plaintext blob. * @param uid The Android user ID associated to this enrollment @@ -58,9 +60,9 @@ interface IGateKeeperService { * @param enrolledPasswordHandle The handle against which the provided password will be * verified. * @param The plaintext blob to verify against enrolledPassword. - * @return an opaque attestation of authentication on success, or null. + * @return a VerifyResponse with an attestation, or null on failure. */ - byte[] verifyChallenge(int uid, long challenge, in byte[] enrolledPasswordHandle, + GateKeeperResponse verifyChallenge(int uid, long challenge, in byte[] enrolledPasswordHandle, in byte[] providedPassword); /** diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index dd3cedc..db19f7a 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -79,6 +79,7 @@ public class ZenModeConfig implements Parcelable { private static final int XML_VERSION = 2; private static final String ZEN_TAG = "zen"; private static final String ZEN_ATT_VERSION = "version"; + private static final String ZEN_ATT_USER = "user"; private static final String ALLOW_TAG = "allow"; private static final String ALLOW_ATT_CALLS = "calls"; private static final String ALLOW_ATT_REPEAT_CALLERS = "repeatCallers"; @@ -117,6 +118,7 @@ public class ZenModeConfig implements Parcelable { public boolean allowEvents = DEFAULT_ALLOW_EVENTS; public int allowCallsFrom = DEFAULT_SOURCE; public int allowMessagesFrom = DEFAULT_SOURCE; + public int user = UserHandle.USER_OWNER; public ZenRule manualRule; public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>(); @@ -131,6 +133,7 @@ public class ZenModeConfig implements Parcelable { allowEvents = source.readInt() == 1; allowCallsFrom = source.readInt(); allowMessagesFrom = source.readInt(); + user = source.readInt(); manualRule = source.readParcelable(null); final int len = source.readInt(); if (len > 0) { @@ -153,6 +156,7 @@ public class ZenModeConfig implements Parcelable { dest.writeInt(allowEvents ? 1 : 0); dest.writeInt(allowCallsFrom); dest.writeInt(allowMessagesFrom); + dest.writeInt(user); dest.writeParcelable(manualRule, 0); if (!automaticRules.isEmpty()) { final int len = automaticRules.size(); @@ -173,7 +177,8 @@ public class ZenModeConfig implements Parcelable { @Override public String toString() { return new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[') - .append("allowCalls=").append(allowCalls) + .append("user=").append(user) + .append(",allowCalls=").append(allowCalls) .append(",allowRepeatCallers=").append(allowRepeatCallers) .append(",allowMessages=").append(allowMessages) .append(",allowCallsFrom=").append(sourceToString(allowCallsFrom)) @@ -185,6 +190,68 @@ public class ZenModeConfig implements Parcelable { .append(']').toString(); } + private Diff diff(ZenModeConfig to) { + final Diff d = new Diff(); + if (to == null) { + return d.addLine("config", "delete"); + } + if (user != to.user) { + d.addLine("user", user, to.user); + } + if (allowCalls != to.allowCalls) { + d.addLine("allowCalls", allowCalls, to.allowCalls); + } + if (allowRepeatCallers != to.allowRepeatCallers) { + d.addLine("allowRepeatCallers", allowRepeatCallers, to.allowRepeatCallers); + } + if (allowMessages != to.allowMessages) { + d.addLine("allowMessages", allowMessages, to.allowMessages); + } + if (allowCallsFrom != to.allowCallsFrom) { + d.addLine("allowCallsFrom", allowCallsFrom, to.allowCallsFrom); + } + if (allowMessagesFrom != to.allowMessagesFrom) { + d.addLine("allowMessagesFrom", allowMessagesFrom, to.allowMessagesFrom); + } + if (allowReminders != to.allowReminders) { + d.addLine("allowReminders", allowReminders, to.allowReminders); + } + if (allowEvents != to.allowEvents) { + d.addLine("allowEvents", allowEvents, to.allowEvents); + } + final ArraySet<String> allRules = new ArraySet<>(); + addKeys(allRules, automaticRules); + addKeys(allRules, to.automaticRules); + final int N = allRules.size(); + for (int i = 0; i < N; i++) { + final String rule = allRules.valueAt(i); + final ZenRule fromRule = automaticRules != null ? automaticRules.get(rule) : null; + final ZenRule toRule = to.automaticRules != null ? to.automaticRules.get(rule) : null; + ZenRule.appendDiff(d, "automaticRule[" + rule + "]", fromRule, toRule); + } + ZenRule.appendDiff(d, "manualRule", manualRule, to.manualRule); + return d; + } + + public static Diff diff(ZenModeConfig from, ZenModeConfig to) { + if (from == null) { + final Diff d = new Diff(); + if (to != null) { + d.addLine("config", "insert"); + } + return d; + } + return from.diff(to); + } + + private static <T> void addKeys(ArraySet<T> set, ArrayMap<T, ?> map) { + if (map != null) { + for (int i = 0; i < map.size(); i++) { + set.add(map.keyAt(i)); + } + } + } + public boolean isValid() { if (!isValidManualRule(manualRule)) return false; final int N = automaticRules.size(); @@ -249,6 +316,7 @@ public class ZenModeConfig implements Parcelable { && other.allowMessagesFrom == allowMessagesFrom && other.allowReminders == allowReminders && other.allowEvents == allowEvents + && other.user == user && Objects.equals(other.automaticRules, automaticRules) && Objects.equals(other.manualRule, manualRule); } @@ -256,7 +324,7 @@ public class ZenModeConfig implements Parcelable { @Override public int hashCode() { return Objects.hash(allowCalls, allowRepeatCallers, allowMessages, allowCallsFrom, - allowMessagesFrom, allowReminders, allowEvents, automaticRules, manualRule); + allowMessagesFrom, allowReminders, allowEvents, user, automaticRules, manualRule); } private static String toDayList(int[] days) { @@ -312,6 +380,7 @@ public class ZenModeConfig implements Parcelable { final XmlV1 v1 = XmlV1.readXml(parser); return migration.migrate(v1); } + rt.user = safeInt(parser, ZEN_ATT_USER, rt.user); while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { tag = parser.getName(); if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) { @@ -341,10 +410,10 @@ public class ZenModeConfig implements Parcelable { rt.allowMessagesFrom = DEFAULT_SOURCE; } } else if (MANUAL_TAG.equals(tag)) { - rt.manualRule = readRuleXml(parser, false /*conditionRequired*/); + rt.manualRule = readRuleXml(parser); } else if (AUTOMATIC_TAG.equals(tag)) { final String id = parser.getAttributeValue(null, RULE_ATT_ID); - final ZenRule automaticRule = readRuleXml(parser, true /*conditionRequired*/); + final ZenRule automaticRule = readRuleXml(parser); if (id != null && automaticRule != null) { rt.automaticRules.put(id, automaticRule); } @@ -357,6 +426,7 @@ public class ZenModeConfig implements Parcelable { public void writeXml(XmlSerializer out) throws IOException { out.startTag(null, ZEN_TAG); out.attribute(null, ZEN_ATT_VERSION, Integer.toString(XML_VERSION)); + out.attribute(null, ZEN_ATT_USER, Integer.toString(user)); out.startTag(null, ALLOW_TAG); out.attribute(null, ALLOW_ATT_CALLS, Boolean.toString(allowCalls)); @@ -385,7 +455,7 @@ public class ZenModeConfig implements Parcelable { out.endTag(null, ZEN_TAG); } - public static ZenRule readRuleXml(XmlPullParser parser, boolean conditionRequired) { + public static ZenRule readRuleXml(XmlPullParser parser) { final ZenRule rt = new ZenRule(); rt.enabled = safeBoolean(parser, RULE_ATT_ENABLED, true); rt.snoozing = safeBoolean(parser, RULE_ATT_SNOOZING, false); @@ -731,7 +801,7 @@ public class ZenModeConfig implements Parcelable { .authority(SYSTEM_AUTHORITY) .appendPath(EVENT_PATH) .appendQueryParameter("userId", Long.toString(event.userId)) - .appendQueryParameter("calendar", Long.toString(event.calendar)) + .appendQueryParameter("calendar", event.calendar != null ? event.calendar : "") .appendQueryParameter("reply", Integer.toString(event.reply)) .build(); } @@ -749,21 +819,21 @@ public class ZenModeConfig implements Parcelable { if (!isEvent) return null; final EventInfo rt = new EventInfo(); rt.userId = tryParseInt(conditionId.getQueryParameter("userId"), UserHandle.USER_NULL); - rt.calendar = tryParseLong(conditionId.getQueryParameter("calendar"), - EventInfo.ANY_CALENDAR); + rt.calendar = conditionId.getQueryParameter("calendar"); + if (TextUtils.isEmpty(rt.calendar) || tryParseLong(rt.calendar, -1L) != -1L) { + rt.calendar = null; + } rt.reply = tryParseInt(conditionId.getQueryParameter("reply"), 0); return rt; } public static class EventInfo { - public static final long ANY_CALENDAR = 0; - public static final int REPLY_ANY_EXCEPT_NO = 0; public static final int REPLY_YES_OR_MAYBE = 1; public static final int REPLY_YES = 2; public int userId = UserHandle.USER_NULL; // USER_NULL = unspecified - use current user - public long calendar = ANY_CALENDAR; // CalendarContract.Calendars._ID, or ANY_CALENDAR + public String calendar; // CalendarContract.Calendars.OWNER_ACCOUNT, or null for any public int reply; @Override @@ -776,7 +846,7 @@ public class ZenModeConfig implements Parcelable { if (!(o instanceof EventInfo)) return false; final EventInfo other = (EventInfo) o; return userId == other.userId - && calendar == other.calendar + && Objects.equals(calendar, other.calendar) && reply == other.reply; } @@ -790,7 +860,6 @@ public class ZenModeConfig implements Parcelable { public static int resolveUserId(int userId) { return userId == UserHandle.USER_NULL ? ActivityManager.getCurrentUser() : userId; - } } @@ -915,6 +984,45 @@ public class ZenModeConfig implements Parcelable { .append(']').toString(); } + private static void appendDiff(Diff d, String item, ZenRule from, ZenRule to) { + if (d == null) return; + if (from == null) { + if (to != null) { + d.addLine(item, "insert"); + } + return; + } + from.appendDiff(d, item, to); + } + + private void appendDiff(Diff d, String item, ZenRule to) { + if (to == null) { + d.addLine(item, "delete"); + return; + } + if (enabled != to.enabled) { + d.addLine(item, "enabled", enabled, to.enabled); + } + if (snoozing != to.snoozing) { + d.addLine(item, "snoozing", snoozing, to.snoozing); + } + if (!Objects.equals(name, to.name)) { + d.addLine(item, "name", name, to.name); + } + if (zenMode != to.zenMode) { + d.addLine(item, "zenMode", zenMode, to.zenMode); + } + if (!Objects.equals(conditionId, to.conditionId)) { + d.addLine(item, "conditionId", conditionId, to.conditionId); + } + if (!Objects.equals(condition, to.condition)) { + d.addLine(item, "condition", condition, to.condition); + } + if (!Objects.equals(component, to.component)) { + d.addLine(item, "component", component, to.component); + } + } + @Override public boolean equals(Object o) { if (!(o instanceof ZenRule)) return false; @@ -1073,4 +1181,34 @@ public class ZenModeConfig implements Parcelable { ZenModeConfig migrate(XmlV1 v1); } + public static class Diff { + private final ArrayList<String> lines = new ArrayList<>(); + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("Diff["); + final int N = lines.size(); + for (int i = 0; i < N; i++) { + if (i > 0) { + sb.append(','); + } + sb.append(lines.get(i)); + } + return sb.append(']').toString(); + } + + private Diff addLine(String item, String action) { + lines.add(item + ":" + action); + return this; + } + + public Diff addLine(String item, String subitem, Object from, Object to) { + return addLine(item + "." + subitem, from, to); + } + + public Diff addLine(String item, Object from, Object to) { + return addLine(item, from + "->" + to); + } + } + } diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl index 7c90261..894edac 100644 --- a/core/java/android/service/voice/IVoiceInteractionSession.aidl +++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl @@ -16,6 +16,8 @@ package android.service.voice; +import android.app.AssistContent; +import android.app.AssistStructure; import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; @@ -28,7 +30,7 @@ import com.android.internal.app.IVoiceInteractionSessionShowCallback; oneway interface IVoiceInteractionSession { void show(in Bundle sessionArgs, int flags, IVoiceInteractionSessionShowCallback showCallback); void hide(); - void handleAssist(in Bundle assistData); + void handleAssist(in Bundle assistData, in AssistStructure structure, in AssistContent content); void handleScreenshot(in Bitmap screenshot); void taskStarted(in Intent intent, int taskId); void taskFinished(in Intent intent, int taskId); diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index 77e2125..8119049 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -70,25 +70,6 @@ public class VoiceInteractionService extends Service { */ public static final String SERVICE_META_DATA = "android.voice_interaction"; - /** - * Flag for use with {@link #showSession}: request that the session be started with - * assist data from the currently focused activity. - */ - public static final int START_WITH_ASSIST = 1<<0; - - /** - * @hide - * Flag for use with {@link #showSession}: request that the session be started with - * a screen shot of the currently focused activity. - */ - public static final int START_WITH_SCREENSHOT = 1<<1; - - /** - * Flag for use with {@link #showSession}: indicate that the session has been started from the - * system assist gesture. - */ - public static final int START_SOURCE_ASSIST_GESTURE = 1<<2; - IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() { @Override public void ready() { mHandler.sendEmptyMessage(MSG_READY); @@ -176,6 +157,10 @@ public class VoiceInteractionService extends Service { * Request that the associated {@link android.service.voice.VoiceInteractionSession} be * shown to the user, starting it if necessary. * @param args Arbitrary arguments that will be propagated to the session. + * @param flags Indicates additional optional behavior that should be performed. May + * be {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} + * to request that the system generate and deliver assist data on the current foreground + * app as part of showing the session UI. */ public void showSession(Bundle args, int flags) { if (mSystemService == null) { diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index f122d10..48ad5a8 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -16,6 +16,7 @@ package android.service.voice; +import android.app.AssistContent; import android.app.AssistStructure; import android.app.Dialog; import android.app.Instrumentation; @@ -67,11 +68,29 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; * when done. It can also initiate voice interactions with applications by calling * {@link #startVoiceActivity}</p>. */ -public abstract class VoiceInteractionSession implements KeyEvent.Callback, - ComponentCallbacks2 { +public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCallbacks2 { static final String TAG = "VoiceInteractionSession"; static final boolean DEBUG = true; + /** + * Flag received in {@link #onShow}: originator requested that the session be started with + * assist data from the currently focused activity. + */ + public static final int SHOW_WITH_ASSIST = 1<<0; + + /** + * @hide + * Flag received in {@link #onShow}: originator requested that the session be started with + * a screen shot of the currently focused activity. + */ + public static final int SHOW_WITH_SCREENSHOT = 1<<1; + + /** + * Flag for use with {@link #onShow}: indicates that the session has been started from the + * system assist gesture. + */ + public static final int SHOW_SOURCE_ASSIST_GESTURE = 1<<2; + final Context mContext; final HandlerCaller mHandlerCaller; @@ -104,10 +123,12 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, @Override public IVoiceInteractorRequest startConfirmation(String callingPackage, IVoiceInteractorCallback callback, CharSequence prompt, Bundle extras) { - Request request = newRequest(callback); - mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_CONFIRMATION, - new Caller(callingPackage, Binder.getCallingUid()), request, - prompt, extras)); + ConfirmationRequest request = new ConfirmationRequest(callingPackage, + Binder.getCallingUid(), callback, VoiceInteractionSession.this, + prompt, extras); + addRequest(request); + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_CONFIRMATION, + request)); return request.mInterface; } @@ -115,47 +136,54 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, public IVoiceInteractorRequest startPickOption(String callingPackage, IVoiceInteractorCallback callback, CharSequence prompt, VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) { - Request request = newRequest(callback); - mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOOO(MSG_START_PICK_OPTION, - new Caller(callingPackage, Binder.getCallingUid()), request, - prompt, options, extras)); + PickOptionRequest request = new PickOptionRequest(callingPackage, + Binder.getCallingUid(), callback, VoiceInteractionSession.this, + prompt, options, extras); + addRequest(request); + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_PICK_OPTION, + request)); return request.mInterface; } @Override public IVoiceInteractorRequest startCompleteVoice(String callingPackage, IVoiceInteractorCallback callback, CharSequence message, Bundle extras) { - Request request = newRequest(callback); - mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_COMPLETE_VOICE, - new Caller(callingPackage, Binder.getCallingUid()), request, - message, extras)); + CompleteVoiceRequest request = new CompleteVoiceRequest(callingPackage, + Binder.getCallingUid(), callback, VoiceInteractionSession.this, + message, extras); + addRequest(request); + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_COMPLETE_VOICE, + request)); return request.mInterface; } @Override public IVoiceInteractorRequest startAbortVoice(String callingPackage, IVoiceInteractorCallback callback, CharSequence message, Bundle extras) { - Request request = newRequest(callback); - mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_ABORT_VOICE, - new Caller(callingPackage, Binder.getCallingUid()), request, - message, extras)); + AbortVoiceRequest request = new AbortVoiceRequest(callingPackage, + Binder.getCallingUid(), callback, VoiceInteractionSession.this, + message, extras); + addRequest(request); + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_ABORT_VOICE, + request)); return request.mInterface; } @Override public IVoiceInteractorRequest startCommand(String callingPackage, IVoiceInteractorCallback callback, String command, Bundle extras) { - Request request = newRequest(callback); - mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_COMMAND, - new Caller(callingPackage, Binder.getCallingUid()), request, - command, extras)); + CommandRequest request = new CommandRequest(callingPackage, + Binder.getCallingUid(), callback, VoiceInteractionSession.this, + command, extras); + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_COMMAND, + request)); return request.mInterface; } @Override public boolean[] supportsCommands(String callingPackage, String[] commands) { Message msg = mHandlerCaller.obtainMessageIOO(MSG_SUPPORTS_COMMANDS, - 0, new Caller(callingPackage, Binder.getCallingUid()), commands); + 0, commands, null); SomeArgs args = mHandlerCaller.sendMessageAndWait(msg); if (args != null) { boolean[] res = (boolean[])args.arg1; @@ -180,21 +208,16 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, } @Override - public void handleAssist(Bundle assistBundle) { + public void handleAssist(Bundle data, AssistStructure structure, + AssistContent content) { // We want to pre-warm the AssistStructure before handing it off to the main // thread. There is a strong argument to be made that it should be handed // through as a separate param rather than part of the assistBundle. - if (assistBundle != null) { - Bundle assistContext = assistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT); - if (assistContext != null) { - AssistStructure as = AssistStructure.getAssistStructure(assistContext); - if (as != null) { - as.ensureData(); - } - } + if (structure != null) { + structure.ensureData(); } - mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_HANDLE_ASSIST, - assistBundle)); + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOO(MSG_HANDLE_ASSIST, + data, structure, content)); } @Override @@ -226,7 +249,16 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, } }; - public static class Request { + /** @hide */ + public static class Caller { + } + + /** + * Base class representing a request from a voice-driver app to perform a particular + * voice operation with the user. See related subclasses for the types of requests + * that are possible. + */ + public static class Request extends Caller { final IVoiceInteractorRequest mInterface = new IVoiceInteractorRequest.Stub() { @Override public void cancel() throws RemoteException { @@ -237,12 +269,40 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, } } }; + final String mCallingPackage; + final int mCallingUid; final IVoiceInteractorCallback mCallback; final WeakReference<VoiceInteractionSession> mSession; + final Bundle mExtras; - Request(IVoiceInteractorCallback callback, VoiceInteractionSession session) { + Request(String packageName, int uid, IVoiceInteractorCallback callback, + VoiceInteractionSession session, Bundle extras) { + mCallingPackage = packageName; + mCallingUid = uid; mCallback = callback; mSession = session.mWeakRef; + mExtras = extras; + } + + /** + * Return the uid of the application that initiated the request. + */ + public int getCallingUid() { + return mCallingUid; + } + + /** + * Return the package name of the application that initiated the request. + */ + public String getCallingPackage() { + return mCallingPackage; + } + + /** + * Return any additional extra information that was supplied as part of the request. + */ + public Bundle getExtras() { + return mExtras; } void finishRequest() { @@ -259,6 +319,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, } } + /** @hide */ public void sendConfirmResult(boolean confirmed, Bundle result) { try { if (DEBUG) Log.d(TAG, "sendConfirmResult: req=" + mInterface @@ -269,6 +330,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, } } + /** @hide */ public void sendPickOptionResult(boolean finished, VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) { try { @@ -283,6 +345,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, } } + /** @hide */ public void sendCompleteVoiceResult(Bundle result) { try { if (DEBUG) Log.d(TAG, "sendCompleteVoiceResult: req=" + mInterface @@ -293,6 +356,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, } } + /** @hide */ public void sendAbortVoiceResult(Bundle result) { try { if (DEBUG) Log.d(TAG, "sendConfirmResult: req=" + mInterface @@ -303,6 +367,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, } } + /** @hide */ public void sendCommandResult(boolean finished, Bundle result) { try { if (DEBUG) Log.d(TAG, "sendCommandResult: req=" + mInterface @@ -315,7 +380,15 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, } } + /** @hide */ public void sendCancelResult() { + cancel(); + } + + /** + * ASk the app to cancel this current request. + */ + public void cancel() { try { if (DEBUG) Log.d(TAG, "sendCancelResult: req=" + mInterface); finishRequest(); @@ -325,13 +398,200 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, } } - public static class Caller { - final String packageName; - final int uid; + /** + * A request for confirmation from the user of an operation, as per + * {@link android.app.VoiceInteractor.ConfirmationRequest + * VoiceInteractor.ConfirmationRequest}. + */ + public static final class ConfirmationRequest extends Request { + final CharSequence mPrompt; - Caller(String _packageName, int _uid) { - packageName = _packageName; - uid = _uid; + ConfirmationRequest(String packageName, int uid, IVoiceInteractorCallback callback, + VoiceInteractionSession session, CharSequence prompt, Bundle extras) { + super(packageName, uid, callback, session, extras); + mPrompt = prompt; + } + + /** + * Return the prompt informing the user of what will happen, as per + * {@link android.app.VoiceInteractor.ConfirmationRequest + * VoiceInteractor.ConfirmationRequest}. + */ + public CharSequence getPrompt() { + return mPrompt; + } + + /** + * Report that the voice interactor has confirmed the operation with the user, resulting + * in a call to + * {@link android.app.VoiceInteractor.ConfirmationRequest#onConfirmationResult + * VoiceInteractor.ConfirmationRequest.onConfirmationResult}. + */ + public void sendConfirmationResult(boolean confirmed, Bundle result) { + sendConfirmResult(confirmed, result); + } + } + + /** + * A request for the user to pick from a set of option, as per + * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. + */ + public static final class PickOptionRequest extends Request { + final CharSequence mPrompt; + final VoiceInteractor.PickOptionRequest.Option[] mOptions; + + PickOptionRequest(String packageName, int uid, IVoiceInteractorCallback callback, + VoiceInteractionSession session, CharSequence prompt, + VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) { + super(packageName, uid, callback, session, extras); + mPrompt = prompt; + mOptions = options; + } + + /** + * Return the prompt informing the user of what they are picking, as per + * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. + */ + public CharSequence getPrompt() { + return mPrompt; + } + + /** + * Return the set of options the user is picking from, as per + * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. + */ + public VoiceInteractor.PickOptionRequest.Option[] getOptions() { + return mOptions; + } + + /** + * Report an intermediate option selection from the request, without completing it (the + * request is still active and the app is waiting for the final option selection), + * resulting in a call to + * {@link android.app.VoiceInteractor.PickOptionRequest#onPickOptionResult + * VoiceInteractor.PickOptionRequest.onPickOptionResult} with false for finished. + */ + public void sendIntermediatePickOptionResult( + VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) { + sendPickOptionResult(false, selections, result); + } + + /** + * Report the final option selection for the request, completing the request + * and resulting in a call to + * {@link android.app.VoiceInteractor.PickOptionRequest#onPickOptionResult + * VoiceInteractor.PickOptionRequest.onPickOptionResult} with false for finished. + */ + public void sendPickOptionResult( + VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) { + sendPickOptionResult(true, selections, result); + } + } + + /** + * A request to simply inform the user that the voice operation has completed, as per + * {@link android.app.VoiceInteractor.CompleteVoiceRequest + * VoiceInteractor.CompleteVoiceRequest}. + */ + public static final class CompleteVoiceRequest extends Request { + final CharSequence mMessage; + + CompleteVoiceRequest(String packageName, int uid, IVoiceInteractorCallback callback, + VoiceInteractionSession session, CharSequence message, Bundle extras) { + super(packageName, uid, callback, session, extras); + mMessage = message; + } + + /** + * Return the message informing the user of the completion, as per + * {@link android.app.VoiceInteractor.CompleteVoiceRequest + * VoiceInteractor.CompleteVoiceRequest}. + */ + public CharSequence getMessage() { + return mMessage; + } + + /** + * Report that the voice interactor has finished completing the voice operation, resulting + * in a call to + * {@link android.app.VoiceInteractor.CompleteVoiceRequest#onCompleteResult + * VoiceInteractor.CompleteVoiceRequest.onCompleteResult}. + */ + public void sendCompleteResult(Bundle result) { + sendCompleteVoiceResult(result); + } + } + + /** + * A request to report that the current user interaction can not be completed with voice, as per + * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}. + */ + public static final class AbortVoiceRequest extends Request { + final CharSequence mMessage; + + AbortVoiceRequest(String packageName, int uid, IVoiceInteractorCallback callback, + VoiceInteractionSession session, CharSequence message, Bundle extras) { + super(packageName, uid, callback, session, extras); + mMessage = message; + } + + /** + * Return the message informing the user of the problem, as per + * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}. + */ + public CharSequence getMessage() { + return mMessage; + } + + /** + * Report that the voice interactor has finished aborting the voice operation, resulting + * in a call to + * {@link android.app.VoiceInteractor.AbortVoiceRequest#onAbortResult + * VoiceInteractor.AbortVoiceRequest.onAbortResult}. + */ + public void sendAbortResult(Bundle result) { + sendAbortVoiceResult(result); + } + } + + /** + * A generic vendor-specific request, as per + * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}. + */ + public static final class CommandRequest extends Request { + final String mCommand; + + CommandRequest(String packageName, int uid, IVoiceInteractorCallback callback, + VoiceInteractionSession session, String command, Bundle extras) { + super(packageName, uid, callback, session, extras); + mCommand = command; + } + + /** + * Return the command that is being executed, as per + * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}. + */ + public String getCommand() { + return mCommand; + } + + /** + * Report an intermediate result of the request, without completing it (the request + * is still active and the app is waiting for the final result), resulting in a call to + * {@link android.app.VoiceInteractor.CommandRequest#onCommandResult + * VoiceInteractor.CommandRequest.onCommandResult} with false for isCompleted. + */ + public void sendIntermediateResult(Bundle result) { + sendCommandResult(false, result); + } + + /** + * Report the final result of the request, completing the request and resulting in a call to + * {@link android.app.VoiceInteractor.CommandRequest#onCommandResult + * VoiceInteractor.CommandRequest.onCommandResult} with true for isCompleted. + */ + public void sendResult(Bundle result) { + sendCommandResult(true, result); } } @@ -358,50 +618,33 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, SomeArgs args; switch (msg.what) { case MSG_START_CONFIRMATION: - args = (SomeArgs)msg.obj; - if (DEBUG) Log.d(TAG, "onConfirm: req=" + ((Request) args.arg2).mInterface - + " prompt=" + args.arg3 + " extras=" + args.arg4); - onConfirm((Caller)args.arg1, (Request)args.arg2, (CharSequence)args.arg3, - (Bundle)args.arg4); + if (DEBUG) Log.d(TAG, "onConfirm: req=" + msg.obj); + onRequestConfirmation((ConfirmationRequest) msg.obj); break; case MSG_START_PICK_OPTION: - args = (SomeArgs)msg.obj; - if (DEBUG) Log.d(TAG, "onPickOption: req=" + ((Request) args.arg2).mInterface - + " prompt=" + args.arg3 + " options=" + args.arg4 - + " extras=" + args.arg5); - onPickOption((Caller)args.arg1, (Request)args.arg2, (CharSequence)args.arg3, - (VoiceInteractor.PickOptionRequest.Option[])args.arg4, - (Bundle)args.arg5); + if (DEBUG) Log.d(TAG, "onPickOption: req=" + msg.obj); + onRequestPickOption((PickOptionRequest) msg.obj); break; case MSG_START_COMPLETE_VOICE: - args = (SomeArgs)msg.obj; - if (DEBUG) Log.d(TAG, "onCompleteVoice: req=" + ((Request) args.arg2).mInterface - + " message=" + args.arg3 + " extras=" + args.arg4); - onCompleteVoice((Caller) args.arg1, (Request) args.arg2, - (CharSequence) args.arg3, (Bundle) args.arg4); + if (DEBUG) Log.d(TAG, "onCompleteVoice: req=" + msg.obj); + onRequestCompleteVoice((CompleteVoiceRequest) msg.obj); break; case MSG_START_ABORT_VOICE: - args = (SomeArgs)msg.obj; - if (DEBUG) Log.d(TAG, "onAbortVoice: req=" + ((Request) args.arg2).mInterface - + " message=" + args.arg3 + " extras=" + args.arg4); - onAbortVoice((Caller) args.arg1, (Request) args.arg2, (CharSequence) args.arg3, - (Bundle) args.arg4); + if (DEBUG) Log.d(TAG, "onAbortVoice: req=" + msg.obj); + onRequestAbortVoice((AbortVoiceRequest) msg.obj); break; case MSG_START_COMMAND: - args = (SomeArgs)msg.obj; - if (DEBUG) Log.d(TAG, "onCommand: req=" + ((Request) args.arg2).mInterface - + " command=" + args.arg3 + " extras=" + args.arg4); - onCommand((Caller) args.arg1, (Request) args.arg2, (String) args.arg3, - (Bundle) args.arg4); + if (DEBUG) Log.d(TAG, "onCommand: req=" + msg.obj); + onRequestCommand((CommandRequest) msg.obj); break; case MSG_SUPPORTS_COMMANDS: args = (SomeArgs)msg.obj; - if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg2); - args.arg1 = onGetSupportedCommands((Caller) args.arg1, (String[]) args.arg2); + if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg1); + args.arg1 = onGetSupportedCommands((String[]) args.arg1); break; case MSG_CANCEL: if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request)msg.obj)); - onCancel((Request)msg.obj); + onCancelRequest((Request) msg.obj); break; case MSG_TASK_STARTED: if (DEBUG) Log.d(TAG, "onTaskStarted: intent=" + msg.obj @@ -422,8 +665,11 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, doDestroy(); break; case MSG_HANDLE_ASSIST: - if (DEBUG) Log.d(TAG, "onHandleAssist: " + msg.obj); - onHandleAssist((Bundle) msg.obj); + args = (SomeArgs)msg.obj; + if (DEBUG) Log.d(TAG, "onHandleAssist: data=" + args.arg1 + + " structure=" + args.arg2 + " content=" + args.arg3); + onHandleAssist((Bundle) args.arg1, (AssistStructure) args.arg2, + (AssistContent) args.arg3); break; case MSG_HANDLE_SCREENSHOT: if (DEBUG) Log.d(TAG, "onHandleScreenshot: " + msg.obj); @@ -527,12 +773,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, return mContext; } - Request newRequest(IVoiceInteractorCallback callback) { - synchronized (this) { - Request req = new Request(callback, this); - mActiveRequests.put(req.mInterface.asBinder(), req); - return req; - } + void addRequest(Request req) { + mActiveRequests.put(req.mInterface.asBinder(), req); } Request removeRequest(IBinder reqInterface) { @@ -631,7 +873,12 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content); } + /** @hide */ public void show() { + show(null, 0); + } + + public void show(Bundle args, int showFlags) { try { mSystemService.showSessionFromSession(mToken, null, 0); } catch (RemoteException e) { @@ -645,11 +892,11 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, } } - /** TODO: remove */ + /** @hide */ public void showWindow() { } - /** TODO: remove */ + /** @hide */ public void hideWindow() { } @@ -678,7 +925,9 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, * <p>As the voice activity runs, it can retrieve a {@link android.app.VoiceInteractor} * through which it can perform voice interactions through your session. These requests * for voice interactions will appear as callbacks on {@link #onGetSupportedCommands}, - * {@link #onConfirm}, {@link #onCommand}, and {@link #onCancel}. + * {@link #onRequestConfirmation}, {@link #onRequestPickOption}, + * {@link #onRequestCompleteVoice}, {@link #onRequestAbortVoice}, + * or {@link #onRequestCommand} * * <p>You will receive a call to {@link #onTaskStarted} when the task starts up * and {@link #onTaskFinished} when the last activity has finished. @@ -749,8 +998,25 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, } } + /** + * Initiatize a new session. At this point you don't know exactly what this + * session will be used for; you will find that out in {@link #onShow}. + */ + public void onCreate() { + doOnCreate(); + } + /** @hide */ public void onCreate(Bundle args) { + doOnCreate(); + } + + /** @hide */ + public void onCreate(Bundle args, int showFlags) { + doOnCreate(); + } + + private void doOnCreate() { mTheme = mTheme != 0 ? mTheme : com.android.internal.R.style.Theme_DeviceDefault_VoiceInteractionSession; mInflater = (LayoutInflater)mContext.getSystemService( @@ -767,15 +1033,6 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, } /** - * Initiatize a new session. The given args and showFlags are the initial values - * passed to {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}, - * if possible. Normally you should handle these in {@link #onShow}. - */ - public void onCreate(Bundle args, int showFlags) { - onCreate(args); - } - - /** * Called when the session UI is going to be shown. This is called after * {@link #onCreateContentView} (if the session's content UI needed to be created) and * immediately prior to the window being shown. This may be called while the window @@ -817,9 +1074,22 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, } + /** @hide */ public void onHandleAssist(Bundle assistBundle) { } + public void onHandleAssist(Bundle data, AssistStructure structure, AssistContent content) { + if (data != null) { + Bundle assistContext = data.getBundle(Intent.EXTRA_ASSIST_CONTEXT); + if (assistContext != null) { + assistContext.putParcelable(AssistStructure.ASSIST_KEY, structure); + assistContext.putParcelable(AssistContent.ASSIST_KEY, content); + data.putBundle(Intent.EXTRA_ASSIST_CONTEXT, assistContext); + } + } + onHandleAssist(data); + } + /** @hide */ public void onHandleScreenshot(Bitmap screenshot) { } @@ -916,18 +1186,45 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, hide(); } + /** @hide */ + public boolean[] onGetSupportedCommands(Caller caller, String[] commands) { + return new boolean[commands.length]; + } + /** @hide */ + public void onConfirm(Caller caller, Request request, CharSequence prompt, + Bundle extras) { + } + /** @hide */ + public void onPickOption(Caller caller, Request request, CharSequence prompt, + VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) { + } + /** @hide */ + public void onCompleteVoice(Caller caller, Request request, CharSequence message, + Bundle extras) { + request.sendCompleteVoiceResult(null); + } + /** @hide */ + public void onAbortVoice(Caller caller, Request request, CharSequence message, Bundle extras) { + request.sendAbortVoiceResult(null); + } + /** @hide */ + public void onCommand(Caller caller, Request request, String command, Bundle extras) { + } + /** @hide */ + public void onCancel(Request request) { + } + /** * Request to query for what extended commands the session supports. * - * @param caller Who is making the request. * @param commands An array of commands that are being queried. * @return Return an array of booleans indicating which of each entry in the * command array is supported. A true entry in the array indicates the command * is supported; false indicates it is not. The default implementation returns * an array of all false entries. */ - public boolean[] onGetSupportedCommands(Caller caller, String[] commands) { - return new boolean[commands.length]; + public boolean[] onGetSupportedCommands(String[] commands) { + return onGetSupportedCommands(new Caller(), commands); } /** @@ -935,31 +1232,22 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, * corresponding to a {@link android.app.VoiceInteractor.ConfirmationRequest * VoiceInteractor.ConfirmationRequest}. * - * @param caller Who is making the request. * @param request The active request. - * @param prompt The prompt informing the user of what will happen, as per - * {@link android.app.VoiceInteractor.ConfirmationRequest VoiceInteractor.ConfirmationRequest}. - * @param extras Any additional information, as per - * {@link android.app.VoiceInteractor.ConfirmationRequest VoiceInteractor.ConfirmationRequest}. */ - public abstract void onConfirm(Caller caller, Request request, CharSequence prompt, - Bundle extras); + public void onRequestConfirmation(ConfirmationRequest request) { + onConfirm(request, request, request.getPrompt(), request.getExtras()); + } /** * Request for the user to pick one of N options, corresponding to a * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. * - * @param caller Who is making the request. * @param request The active request. - * @param prompt The prompt informing the user of what they are picking, as per - * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. - * @param options The set of options the user is picking from, as per - * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. - * @param extras Any additional information, as per - * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. */ - public abstract void onPickOption(Caller caller, Request request, CharSequence prompt, - VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras); + public void onRequestPickOption(PickOptionRequest request) { + onPickOption(request, request, request.getPrompt(), request.getOptions(), + request.getExtras()); + } /** * Request to complete the voice interaction session because the voice activity successfully @@ -968,18 +1256,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, * VoiceInteractor.CompleteVoiceRequest}. The default implementation just sends an empty * confirmation back to allow the activity to exit. * - * @param caller Who is making the request. * @param request The active request. - * @param message The message informing the user of the problem, as per - * {@link android.app.VoiceInteractor.CompleteVoiceRequest - * VoiceInteractor.CompleteVoiceRequest}. - * @param extras Any additional information, as per - * {@link android.app.VoiceInteractor.CompleteVoiceRequest - * VoiceInteractor.CompleteVoiceRequest}. */ - public void onCompleteVoice(Caller caller, Request request, CharSequence message, - Bundle extras) { - request.sendCompleteVoiceResult(null); + public void onRequestCompleteVoice(CompleteVoiceRequest request) { + onCompleteVoice(request, request, request.getMessage(), request.getExtras()); } /** @@ -989,15 +1269,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, * VoiceInteractor.AbortVoiceRequest}. The default implementation just sends an empty * confirmation back to allow the activity to exit. * - * @param caller Who is making the request. * @param request The active request. - * @param message The message informing the user of the problem, as per - * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}. - * @param extras Any additional information, as per - * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}. */ - public void onAbortVoice(Caller caller, Request request, CharSequence message, Bundle extras) { - request.sendAbortVoiceResult(null); + public void onRequestAbortVoice(AbortVoiceRequest request) { + onAbortVoice(request, request, request.getMessage(), request.getExtras()); } /** @@ -1005,20 +1280,21 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback, * corresponding to a {@link android.app.VoiceInteractor.CommandRequest * VoiceInteractor.CommandRequest}. * - * @param caller Who is making the request. * @param request The active request. - * @param command The command that is being executed, as per - * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}. - * @param extras Any additional information, as per - * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}. */ - public abstract void onCommand(Caller caller, Request request, String command, Bundle extras); + public void onRequestCommand(CommandRequest request) { + onCommand(request, request, request.getCommand(), request.getExtras()); + } /** * Called when the {@link android.app.VoiceInteractor} has asked to cancel a {@link Request} - * that was previously delivered to {@link #onConfirm} or {@link #onCommand}. + * that was previously delivered to {@link #onRequestConfirmation}, + * {@link #onRequestPickOption}, {@link #onRequestCompleteVoice}, {@link #onRequestAbortVoice}, + * or {@link #onRequestCommand}. * * @param request The request that is being canceled. */ - public abstract void onCancel(Request request); + public void onCancelRequest(Request request) { + onCancel(request); + } } diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index b93a4a5..8952807 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -18,7 +18,6 @@ package android.service.wallpaper; import android.content.res.TypedArray; import android.graphics.Canvas; -import android.os.SystemProperties; import android.view.WindowInsets; import com.android.internal.R; @@ -161,9 +160,11 @@ public abstract class WallpaperService extends Service { final Rect mOverscanInsets = new Rect(); final Rect mContentInsets = new Rect(); final Rect mStableInsets = new Rect(); + final Rect mOutsets = new Rect(); final Rect mDispatchedOverscanInsets = new Rect(); final Rect mDispatchedContentInsets = new Rect(); final Rect mDispatchedStableInsets = new Rect(); + final Rect mDispatchedOutsets = new Rect(); final Rect mFinalSystemInsets = new Rect(); final Rect mFinalStableInsets = new Rect(); final Configuration mConfiguration = new Configuration(); @@ -268,7 +269,7 @@ public abstract class WallpaperService extends Service { final BaseIWindow mWindow = new BaseIWindow() { @Override public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, - Rect visibleInsets, Rect stableInsets, boolean reportDraw, + Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig) { Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED, reportDraw ? 1 : 0); @@ -658,30 +659,35 @@ public abstract class WallpaperService extends Service { mInputEventReceiver = new WallpaperInputEventReceiver( mInputChannel, Looper.myLooper()); } - + mSurfaceHolder.mSurfaceLock.lock(); mDrawingAllowed = true; if (!fixedSize) { mLayout.surfaceInsets.set(mIWallpaperEngine.mDisplayPadding); + mLayout.surfaceInsets.left += mOutsets.left; + mLayout.surfaceInsets.top += mOutsets.top; + mLayout.surfaceInsets.right += mOutsets.right; + mLayout.surfaceInsets.bottom += mOutsets.bottom; } else { mLayout.surfaceInsets.set(0, 0, 0, 0); } final int relayoutResult = mSession.relayout( mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets, - mVisibleInsets, mStableInsets, mConfiguration, mSurfaceHolder.mSurface); + mVisibleInsets, mStableInsets, mOutsets, mConfiguration, + mSurfaceHolder.mSurface); if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface + ", frame=" + mWinFrame); - + int w = mWinFrame.width(); int h = mWinFrame.height(); if (!fixedSize) { final Rect padding = mIWallpaperEngine.mDisplayPadding; - w += padding.left + padding.right; - h += padding.top + padding.bottom; + w += padding.left + padding.right + mOutsets.left + mOutsets.right; + h += padding.top + padding.bottom + mOutsets.top + mOutsets.bottom; mOverscanInsets.left += padding.left; mOverscanInsets.top += padding.top; mOverscanInsets.right += padding.right; @@ -705,9 +711,14 @@ public abstract class WallpaperService extends Service { mCurHeight = h; } + if (DEBUG) { + Log.v(TAG, "Wallpaper size has changed: (" + mCurWidth + ", " + mCurHeight); + } + insetsChanged |= !mDispatchedOverscanInsets.equals(mOverscanInsets); insetsChanged |= !mDispatchedContentInsets.equals(mContentInsets); insetsChanged |= !mDispatchedStableInsets.equals(mStableInsets); + insetsChanged |= !mDispatchedOutsets.equals(mOutsets); mSurfaceHolder.setSurfaceFrameSize(w, h); mSurfaceHolder.mSurfaceLock.unlock(); @@ -767,14 +778,21 @@ public abstract class WallpaperService extends Service { if (insetsChanged) { mDispatchedOverscanInsets.set(mOverscanInsets); + mDispatchedOverscanInsets.left += mOutsets.left; + mDispatchedOverscanInsets.top += mOutsets.top; + mDispatchedOverscanInsets.right += mOutsets.right; + mDispatchedOverscanInsets.bottom += mOutsets.bottom; mDispatchedContentInsets.set(mContentInsets); mDispatchedStableInsets.set(mStableInsets); + mDispatchedOutsets.set(mOutsets); mFinalSystemInsets.set(mDispatchedOverscanInsets); mFinalStableInsets.set(mDispatchedStableInsets); - mFinalSystemInsets.bottom = mIWallpaperEngine.mDisplayPadding.bottom; WindowInsets insets = new WindowInsets(mFinalSystemInsets, null, mFinalStableInsets, getResources().getConfiguration().isScreenRound()); + if (DEBUG) { + Log.v(TAG, "dispatching insets=" + insets); + } onApplyWindowInsets(insets); } diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java index dcdbba7..3e74d22 100644 --- a/core/java/android/speech/RecognitionService.java +++ b/core/java/android/speech/RecognitionService.java @@ -21,6 +21,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.app.Service; import android.content.Intent; import android.content.pm.PackageManager; +import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -78,7 +79,7 @@ public abstract class RecognitionService extends Service { switch (msg.what) { case MSG_START_LISTENING: StartListeningArgs args = (StartListeningArgs) msg.obj; - dispatchStartListening(args.mIntent, args.mListener); + dispatchStartListening(args.mIntent, args.mListener, args.mCallingUid); break; case MSG_STOP_LISTENING: dispatchStopListening((IRecognitionListener) msg.obj); @@ -93,7 +94,8 @@ public abstract class RecognitionService extends Service { } }; - private void dispatchStartListening(Intent intent, final IRecognitionListener listener) { + private void dispatchStartListening(Intent intent, final IRecognitionListener listener, + int callingUid) { if (mCurrentCallback == null) { if (DBG) Log.d(TAG, "created new mCurrentCallback, listener = " + listener.asBinder()); try { @@ -107,7 +109,7 @@ public abstract class RecognitionService extends Service { Log.e(TAG, "dead listener on startListening"); return; } - mCurrentCallback = new Callback(listener); + mCurrentCallback = new Callback(listener, callingUid); RecognitionService.this.onStartListening(intent, mCurrentCallback); } else { try { @@ -155,10 +157,12 @@ public abstract class RecognitionService extends Service { public final Intent mIntent; public final IRecognitionListener mListener; + public final int mCallingUid; - public StartListeningArgs(Intent intent, IRecognitionListener listener) { + public StartListeningArgs(Intent intent, IRecognitionListener listener, int callingUid) { this.mIntent = intent; this.mListener = listener; + this.mCallingUid = callingUid; } } @@ -227,9 +231,11 @@ public abstract class RecognitionService extends Service { */ public class Callback { private final IRecognitionListener mListener; + private final int mCallingUid; - private Callback(IRecognitionListener listener) { + private Callback(IRecognitionListener listener, int callingUid) { mListener = listener; + mCallingUid = callingUid; } /** @@ -314,6 +320,14 @@ public abstract class RecognitionService extends Service { public void rmsChanged(float rmsdB) throws RemoteException { mListener.onRmsChanged(rmsdB); } + + /** + * Return the Linux uid assigned to the process that sent you the current transaction that + * is being processed. This is obtained from {@link Binder#getCallingUid()}. + */ + public int getCallingUid() { + return mCallingUid; + } } /** Binder of the recognition service */ @@ -331,7 +345,7 @@ public abstract class RecognitionService extends Service { if (service != null && service.checkPermissions(listener)) { service.mHandler.sendMessage(Message.obtain(service.mHandler, MSG_START_LISTENING, service.new StartListeningArgs( - recognizerIntent, listener))); + recognizerIntent, listener, Binder.getCallingUid()))); } } diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index f176240..f7027f9 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -1121,6 +1121,7 @@ public abstract class Layout { * closest to the specified horizontal position. */ public int getOffsetForHorizontal(int line, float horiz) { + // TODO: use Paint.getOffsetForAdvance to avoid binary search int max = getLineEnd(line) - 1; int min = getLineStart(line); Directions dirs = getLineDirections(line); diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 479242c..605b91d 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -739,16 +739,14 @@ class TextLine { float ret = 0; - int contextLen = contextEnd - contextStart; if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) { if (mCharsValid) { - ret = wp.getTextRunAdvances(mChars, start, runLen, - contextStart, contextLen, runIsRtl, null, 0); + ret = wp.getRunAdvance(mChars, start, contextEnd, contextStart, contextEnd, + runIsRtl, end); } else { int delta = mStart; - ret = wp.getTextRunAdvances(mText, delta + start, - delta + end, delta + contextStart, delta + contextEnd, - runIsRtl, null, 0); + ret = wp.getRunAdvance(mText, delta + start, delta + contextEnd, + delta + contextStart, delta + contextEnd, runIsRtl, delta + end); } } diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index ac98e8a..14ebec7 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -258,7 +258,7 @@ public class DateUtils * Returns a string describing 'time' as a time relative to 'now'. * <p> * Time spans in the past are formatted like "42 minutes ago". - * Time spans in the future are formatted like "in 42 minutes". + * Time spans in the future are formatted like "In 42 minutes". * * @param time the time to describe, in milliseconds * @param now the current time in milliseconds @@ -275,7 +275,7 @@ public class DateUtils * Returns a string describing 'time' as a time relative to 'now'. * <p> * Time spans in the past are formatted like "42 minutes ago". Time spans in - * the future are formatted like "in 42 minutes". + * the future are formatted like "In 42 minutes". * <p> * Can use {@link #FORMAT_ABBREV_RELATIVE} flag to use abbreviated relative * times, like "42 mins ago". diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index 3781d40..6e2d110 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -758,7 +758,10 @@ final class AccessibilityInteractionController { Rect visibleDisplayFrame = mTempRect2; visibleDisplayFrame.set(0, 0, displayWidth, displayHeight); - visibleWinFrame.intersect(visibleDisplayFrame); + if (!visibleWinFrame.intersect(visibleDisplayFrame)) { + // If there's no intersection with display, set visibleWinFrame empty. + visibleDisplayFrame.setEmpty(); + } if (!visibleWinFrame.intersects(boundsInScreen.left, boundsInScreen.top, boundsInScreen.right, boundsInScreen.bottom)) { diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java index b8544c6..ff0af6b 100644 --- a/core/java/android/view/GestureDetector.java +++ b/core/java/android/view/GestureDetector.java @@ -32,6 +32,9 @@ import android.os.Message; * <li>In the {@link View#onTouchEvent(MotionEvent)} method ensure you call * {@link #onTouchEvent(MotionEvent)}. The methods defined in your callback * will be executed when the events occur. + * <li>If listening for {@link OnStylusButtonPressListener#onStylusButtonPress(MotionEvent)} + * you must call {@link #onGenericMotionEvent(MotionEvent)} + * in {@link View#onGenericMotionEvent(MotionEvent)}. * </ul> */ public class GestureDetector { @@ -149,12 +152,14 @@ public class GestureDetector { } /** - * The listener that is used to notify when a stylus button press occurs. + * The listener that is used to notify when a stylus button press occurs. When listening for a + * stylus button press ensure that you call {@link #onGenericMotionEvent(MotionEvent)} in + * {@link View#onGenericMotionEvent(MotionEvent)}. */ public interface OnStylusButtonPressListener { /** * Notified when a stylus button press occurs. This is when the stylus - * is touching the screen and the {@value MotionEvent#BUTTON_SECONDARY} + * is touching the screen and the {@value MotionEvent#BUTTON_STYLUS_PRIMARY} * is pressed. * * @param e The motion event that occurred during the stylus button @@ -241,6 +246,7 @@ public class GestureDetector { private boolean mInStylusButtonPress; private boolean mAlwaysInTapRegion; private boolean mAlwaysInBiggerTapRegion; + private boolean mIgnoreNextUpEvent; private MotionEvent mCurrentDownEvent; private MotionEvent mPreviousUpEvent; @@ -552,18 +558,7 @@ public class GestureDetector { break; case MotionEvent.ACTION_DOWN: - if (mStylusButtonListener != null - && ev.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS - && (ev.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { - if (mStylusButtonListener.onStylusButtonPress(ev)) { - mInStylusButtonPress = true; - handled = true; - mHandler.removeMessages(LONG_PRESS); - mHandler.removeMessages(TAP); - } - } - - if (mDoubleTapListener != null && !mInStylusButtonPress) { + if (mDoubleTapListener != null) { boolean hadTapMessage = mHandler.hasMessages(TAP); if (hadTapMessage) mHandler.removeMessages(TAP); if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage && @@ -592,7 +587,7 @@ public class GestureDetector { mInLongPress = false; mDeferConfirmSingleTap = false; - if (mIsLongpressEnabled && !mInStylusButtonPress) { + if (mIsLongpressEnabled) { mHandler.removeMessages(LONG_PRESS); mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT + LONGPRESS_TIMEOUT); @@ -602,16 +597,6 @@ public class GestureDetector { break; case MotionEvent.ACTION_MOVE: - if (mStylusButtonListener != null && !mInStylusButtonPress && !mInLongPress - && ev.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS - && (ev.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { - if (mStylusButtonListener.onStylusButtonPress(ev)) { - mInStylusButtonPress = true; - handled = true; - mHandler.removeMessages(LONG_PRESS); - mHandler.removeMessages(TAP); - } - } if (mInLongPress || mInStylusButtonPress) { break; } @@ -652,15 +637,12 @@ public class GestureDetector { } else if (mInLongPress) { mHandler.removeMessages(TAP); mInLongPress = false; - } else if (mInStylusButtonPress) { - mHandler.removeMessages(TAP); - mInStylusButtonPress = false; - } else if (mAlwaysInTapRegion) { + } else if (mAlwaysInTapRegion && !mIgnoreNextUpEvent) { handled = mListener.onSingleTapUp(ev); if (mDeferConfirmSingleTap && mDoubleTapListener != null) { mDoubleTapListener.onSingleTapConfirmed(ev); } - } else { + } else if (!mIgnoreNextUpEvent) { // A fling must travel the minimum tap distance final VelocityTracker velocityTracker = mVelocityTracker; @@ -687,6 +669,7 @@ public class GestureDetector { } mIsDoubleTapping = false; mDeferConfirmSingleTap = false; + mIgnoreNextUpEvent = false; mHandler.removeMessages(SHOW_PRESS); mHandler.removeMessages(LONG_PRESS); break; @@ -702,6 +685,43 @@ public class GestureDetector { return handled; } + /** + * Analyzes the given generic motion event and if applicable triggers the + * appropriate callbacks on the {@link OnGestureListener} supplied. + * + * @param ev The current motion event. + * @return true if the {@link OnGestureListener} consumed the event, + * else false. + */ + public boolean onGenericMotionEvent(MotionEvent ev) { + if (mInputEventConsistencyVerifier != null) { + mInputEventConsistencyVerifier.onGenericMotionEvent(ev, 0); + } + + switch (ev.getActionMasked()) { + case MotionEvent.ACTION_BUTTON_PRESS: + if (mStylusButtonListener != null && !mInStylusButtonPress && !mInLongPress + && ev.getActionButton() == MotionEvent.BUTTON_STYLUS_PRIMARY) { + if (mStylusButtonListener.onStylusButtonPress(ev)) { + mInStylusButtonPress = true; + mHandler.removeMessages(LONG_PRESS); + mHandler.removeMessages(TAP); + return true; + } + } + break; + + case MotionEvent.ACTION_BUTTON_RELEASE: + if (mInStylusButtonPress + && ev.getActionButton() == MotionEvent.BUTTON_STYLUS_PRIMARY) { + mInStylusButtonPress = false; + mIgnoreNextUpEvent = true; + } + break; + } + return false; + } + private void cancel() { mHandler.removeMessages(SHOW_PRESS); mHandler.removeMessages(LONG_PRESS); @@ -715,6 +735,7 @@ public class GestureDetector { mDeferConfirmSingleTap = false; mInLongPress = false; mInStylusButtonPress = false; + mIgnoreNextUpEvent = false; } private void cancelTaps() { @@ -727,6 +748,7 @@ public class GestureDetector { mDeferConfirmSingleTap = false; mInLongPress = false; mInStylusButtonPress = false; + mIgnoreNextUpEvent = false; } private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp, diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl index 0fefdc7..9cf3759 100644 --- a/core/java/android/view/IWindow.aidl +++ b/core/java/android/view/IWindow.aidl @@ -46,7 +46,7 @@ oneway interface IWindow { void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor); void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets, - in Rect visibleInsets, in Rect stableInsets, boolean reportDraw, + in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw, in Configuration newConfig); void moved(int newX, int newY); void dispatchAppVisibility(boolean visible); diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index fc0148f..19253dd 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -79,11 +79,13 @@ interface IWindowSession { * contents to make sure the user can see it. This is different than * <var>outContentInsets</var> in that these insets change transiently, * so complex relayout of the window should not happen based on them. + * @param outOutsets Rect in which is placed the dead area of the screen that we would like to + * treat as real display. Example of such area is a chin in some models of wearable devices. * @param outConfiguration New configuration of window, if it is now * becoming visible and the global configuration has changed since it * was last displayed. * @param outSurface Object in which is placed the new display surface. - * + * * @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_SHOW_FOCUS}, * {@link WindowManagerGlobal#RELAYOUT_FIRST_TIME}. */ @@ -91,7 +93,7 @@ interface IWindowSession { int requestedWidth, int requestedHeight, int viewVisibility, int flags, out Rect outFrame, out Rect outOverscanInsets, out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets, - out Configuration outConfig, out Surface outSurface); + out Rect outOutsets, out Configuration outConfig, out Surface outSurface); /** * If a call to relayout() asked to have the surface destroy deferred, diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java index b055efe..7b0f1fb 100644 --- a/core/java/android/view/ScaleGestureDetector.java +++ b/core/java/android/view/ScaleGestureDetector.java @@ -320,8 +320,8 @@ public class ScaleGestureDetector { } final int count = event.getPointerCount(); - final boolean isStylusButtonDown = (event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS) - && (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0; + final boolean isStylusButtonDown = + (event.getButtonState() & MotionEvent.BUTTON_STYLUS_PRIMARY) != 0; final boolean anchoredScaleCancelled = mAnchoredScaleMode == ANCHORED_SCALE_MODE_STYLUS && !isStylusButtonDown; diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 49be57d..160c662 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -106,6 +106,7 @@ public class SurfaceView extends View { final Rect mOverscanInsets = new Rect(); final Rect mContentInsets = new Rect(); final Rect mStableInsets = new Rect(); + final Rect mOutsets = new Rect(); final Configuration mConfiguration = new Configuration(); static final int KEEP_SCREEN_ON_MSG = 1; @@ -519,7 +520,8 @@ public class SurfaceView extends View { visible ? VISIBLE : GONE, WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY, mWinFrame, mOverscanInsets, mContentInsets, - mVisibleInsets, mStableInsets, mConfiguration, mNewSurface); + mVisibleInsets, mStableInsets, mOutsets, mConfiguration, + mNewSurface); if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { mReportDrawNeeded = true; } @@ -654,7 +656,7 @@ public class SurfaceView extends View { @Override public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, - Rect visibleInsets, Rect stableInsets, boolean reportDraw, + Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig) { SurfaceView surfaceView = mSurfaceView.get(); if (surfaceView != null) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 3962b70..cfd504d 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3521,7 +3521,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * the stylus is touching the screen and the button has been pressed, this * is false once the stylus has been lifted. */ - private boolean mInStylusButtonPress = false; + private boolean mInStylusButtonPress; + + /** + * Whether the next up event should be ignored for the purposes of gesture recognition. This is + * true after a stylus button press has occured, when the next up event should not be recognized + * as a tap. + */ + private boolean mIgnoreNextUpEvent; /** * The minimum height of the view. We'll try our best to have the height @@ -4457,47 +4464,60 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private static SparseArray<String> getAttributeMap() { if (mAttributeMap == null) { - mAttributeMap = new SparseArray<String>(); + mAttributeMap = new SparseArray<>(); } return mAttributeMap; } - private void saveAttributeData(AttributeSet attrs, TypedArray a) { - int length = ((attrs == null ? 0 : attrs.getAttributeCount()) + a.getIndexCount()) * 2; - mAttributes = new String[length]; + private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { + final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); + final int indexCount = t.getIndexCount(); + final String[] attributes = new String[(attrsCount + indexCount) * 2]; int i = 0; - if (attrs != null) { - for (i = 0; i < attrs.getAttributeCount(); i += 2) { - mAttributes[i] = attrs.getAttributeName(i); - mAttributes[i + 1] = attrs.getAttributeValue(i); - } + // Store raw XML attributes. + for (int j = 0; j < attrsCount; ++j) { + attributes[i] = attrs.getAttributeName(j); + attributes[i + 1] = attrs.getAttributeValue(j); + i += 2; } - SparseArray<String> attributeMap = getAttributeMap(); - for (int j = 0; j < a.length(); ++j) { - if (a.hasValue(j)) { - try { - int resourceId = a.getResourceId(j, 0); - if (resourceId == 0) { - continue; - } + // Store resolved styleable attributes. + final Resources res = t.getResources(); + final SparseArray<String> attributeMap = getAttributeMap(); + for (int j = 0; j < indexCount; ++j) { + final int index = t.getIndex(j); + if (!t.hasValueOrEmpty(index)) { + // Value is undefined. Skip it. + continue; + } - String resourceName = attributeMap.get(resourceId); - if (resourceName == null) { - resourceName = a.getResources().getResourceName(resourceId); - attributeMap.put(resourceId, resourceName); - } + final int resourceId = t.getResourceId(index, 0); + if (resourceId == 0) { + // Value is not a reference. Skip it. + continue; + } - mAttributes[i] = resourceName; - mAttributes[i + 1] = a.getText(j).toString(); - i += 2; + String resourceName = attributeMap.get(resourceId); + if (resourceName == null) { + try { + resourceName = res.getResourceName(resourceId); } catch (Resources.NotFoundException e) { - // if we can't get the resource name, we just ignore it + resourceName = "0x" + Integer.toHexString(resourceId); } + attributeMap.put(resourceId, resourceName); } + + attributes[i] = resourceName; + attributes[i + 1] = t.getString(index); + i += 2; } + + // Trim to fit contents. + final String[] trimmed = new String[i]; + System.arraycopy(attributes, 0, trimmed, 0, i); + mAttributes = trimmed; } public String toString() { @@ -5218,26 +5238,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Checks for a stylus button press and calls the listener. - * - * @param event The event. - * @return True if the event was consumed. - */ - private boolean performStylusActionOnButtonPress(MotionEvent event) { - if (isStylusButtonPressable() && !mInStylusButtonPress && !mHasPerformedLongPress - && event.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY)) { - if (performStylusButtonPress()) { - mInStylusButtonPress = true; - setPressed(true, event.getX(), event.getY()); - removeTapCallback(); - removeLongPressCallback(); - return true; - } - } - return false; - } - - /** * Performs button-related actions during a touch down event. * * @param event The event. @@ -6351,7 +6351,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } View next = rootView.findViewInsideOutShouldExist(this, mAccessibilityTraversalBeforeId); - if (next != null) { + if (next != null && next.includeForAccessibility()) { info.setTraversalBefore(next); } } @@ -6363,7 +6363,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } View next = rootView.findViewInsideOutShouldExist(this, mAccessibilityTraversalAfterId); - if (next != null) { + if (next != null && next.includeForAccessibility()) { info.setTraversalAfter(next); } } @@ -7363,6 +7363,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Returns the outsets, which areas of the device that aren't a surface, but we would like to + * treat them as such. + * @hide + */ + public void getOutsets(Rect outOutsetRect) { + outOutsetRect.set(mAttachInfo.mOutsets); + } + + /** * Returns the visibility status for this view. * * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. @@ -9358,6 +9367,29 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return true; } + switch (event.getActionMasked()) { + case MotionEvent.ACTION_BUTTON_PRESS: + if (isStylusButtonPressable() && !mInStylusButtonPress && !mHasPerformedLongPress + && event.getActionButton() == MotionEvent.BUTTON_STYLUS_PRIMARY) { + if (performStylusButtonPress()) { + mInStylusButtonPress = true; + setPressed(true, event.getX(), event.getY()); + removeTapCallback(); + removeLongPressCallback(); + return true; + } + } + break; + + case MotionEvent.ACTION_BUTTON_RELEASE: + if (mInStylusButtonPress + && event.getActionButton() == MotionEvent.BUTTON_STYLUS_PRIMARY) { + mInStylusButtonPress = false; + mIgnoreNextUpEvent = true; + } + break; + } + if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); } @@ -10218,10 +10250,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, (viewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE) { switch (action) { case MotionEvent.ACTION_UP: - if (mInStylusButtonPress) { - mInStylusButtonPress = false; - mHasPerformedLongPress = false; - } boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { // take focus if we don't have it already and we should in @@ -10239,7 +10267,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setPressed(true, x, y); } - if (!mHasPerformedLongPress) { + if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { // This is a tap, so remove the longpress check removeLongPressCallback(); @@ -10271,15 +10299,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, removeTapCallback(); } + mIgnoreNextUpEvent = false; break; case MotionEvent.ACTION_DOWN: mHasPerformedLongPress = false; - mInStylusButtonPress = false; - - if (performStylusActionOnButtonPress(event)) { - break; - } if (performButtonActionOnTouchDown(event)) { break; @@ -10309,10 +10333,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setPressed(false); removeTapCallback(); removeLongPressCallback(); - if (mInStylusButtonPress) { - mInStylusButtonPress = false; - mHasPerformedLongPress = false; - } + mInStylusButtonPress = false; + mHasPerformedLongPress = false; + mIgnoreNextUpEvent = false; break; case MotionEvent.ACTION_MOVE: @@ -10328,9 +10351,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setPressed(false); } - } else if (performStylusActionOnButtonPress(event)) { - // Check for stylus button press if we're within the view. - break; } break; } @@ -14493,6 +14513,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, onDetachedFromWindow(); onDetachedFromWindowInternal(); + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null) { + imm.onViewDetachedFromWindow(this); + } + ListenerInfo li = mListenerInfo; final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = li != null ? li.mOnAttachStateChangeListeners : null; @@ -21548,6 +21573,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final Rect mStableInsets = new Rect(); /** + * For windows that include areas that are not covered by real surface these are the outsets + * for real surface. + */ + final Rect mOutsets = new Rect(); + + /** * The internal insets given by this window. This value is * supplied by the client (through * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index a7e739d..e015c04 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -793,7 +793,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @Override public ActionMode startActionModeForChild( View originalView, ActionMode.Callback callback, int type) { - if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED) == 0) { + if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED) == 0 + && type == ActionMode.TYPE_PRIMARY) { ActionMode mode; try { mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED; @@ -1913,6 +1914,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @Override public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) { + if (getAccessibilityNodeProvider() != null) { + return; + } ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true); try { final int childrenCount = children.getChildCount(); @@ -3602,14 +3606,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** - * Sets whether this ViewGroup will clip its children to its padding, if - * padding is present. + * Sets whether this ViewGroup will clip its children to its padding and resize (but not + * clip) any EdgeEffect to the padded region, if padding is present. * <p> * By default, children are clipped to the padding of their parent - * Viewgroup. This clipping behavior is only enabled if padding is non-zero. + * ViewGroup. This clipping behavior is only enabled if padding is non-zero. * - * @param clipToPadding true to clip children to the padding of the - * group, false otherwise + * @param clipToPadding true to clip children to the padding of the group, and resize (but + * not clip) any EdgeEffect to the padded region. False otherwise. * @attr ref android.R.styleable#ViewGroup_clipToPadding */ public void setClipToPadding(boolean clipToPadding) { @@ -3620,13 +3624,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** - * Returns whether this ViewGroup will clip its children to its padding, if - * padding is present. + * Returns whether this ViewGroup will clip its children to its padding, and resize (but + * not clip) any EdgeEffect to the padded region, if padding is present. * <p> * By default, children are clipped to the padding of their parent * Viewgroup. This clipping behavior is only enabled if padding is non-zero. * - * @return true if this ViewGroup clips children to its padding, false otherwise + * @return true if this ViewGroup clips children to its padding and resizes (but doesn't + * clip) any EdgeEffect to the padded region, false otherwise. * * @attr ref android.R.styleable#ViewGroup_clipToPadding */ @@ -5224,12 +5229,20 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager descendant.mTop - descendant.mScrollY); if (clipToBounds) { View p = (View) theParent; - rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop); + boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft, + p.mBottom - p.mTop); + if (!intersected) { + rect.setEmpty(); + } } } else { if (clipToBounds) { View p = (View) theParent; - rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop); + boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft, + p.mBottom - p.mTop); + if (!intersected) { + rect.setEmpty(); + } } rect.offset(descendant.mScrollX - descendant.mLeft, descendant.mScrollY - descendant.mTop); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 89b91f1..e1e0154 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -268,6 +268,7 @@ public final class ViewRootImpl implements ViewParent, final Rect mPendingVisibleInsets = new Rect(); final Rect mPendingStableInsets = new Rect(); final Rect mPendingContentInsets = new Rect(); + final Rect mPendingOutsets = new Rect(); final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets = new ViewTreeObserver.InternalInsetsInfo(); @@ -1267,6 +1268,12 @@ public final class ViewRootImpl implements ViewParent, contentInsets = mPendingContentInsets; stableInsets = mPendingStableInsets; } + Rect outsets = mAttachInfo.mOutsets; + if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) { + contentInsets = new Rect(contentInsets.left + outsets.left, + contentInsets.top + outsets.top, contentInsets.right + outsets.right, + contentInsets.bottom + outsets.bottom); + } mLastWindowInsets = new WindowInsets(contentInsets, null /* windowDecorInsets */, stableInsets, mContext.getResources().getConfiguration().isScreenRound()); @@ -1425,6 +1432,9 @@ public final class ViewRootImpl implements ViewParent, if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: " + mAttachInfo.mVisibleInsets); } + if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) { + insetsChanged = true; + } if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { windowSizeMayChange = true; @@ -1598,6 +1608,7 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mVisibleInsets); final boolean stableInsetsChanged = !mPendingStableInsets.equals( mAttachInfo.mStableInsets); + final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets); if (contentInsetsChanged) { if (mWidth > 0 && mHeight > 0 && lp != null && ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility) @@ -1681,9 +1692,11 @@ public final class ViewRootImpl implements ViewParent, } if (contentInsetsChanged || mLastSystemUiVisibility != mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested - || mLastOverscanRequested != mAttachInfo.mOverscanRequested) { + || mLastOverscanRequested != mAttachInfo.mOverscanRequested + || outsetsChanged) { mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; mLastOverscanRequested = mAttachInfo.mOverscanRequested; + mAttachInfo.mOutsets.set(mPendingOutsets); mApplyInsetsRequested = false; dispatchApplyInsets(host); } @@ -2791,7 +2804,11 @@ public final class ViewRootImpl implements ViewParent, final AttachInfo attachInfo = mAttachInfo; bounds.offset(0, attachInfo.mViewRootImpl.mScrollY); bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop); - bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth, attachInfo.mViewRootImpl.mHeight); + if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth, + attachInfo.mViewRootImpl.mHeight)) { + // If no intersection, set bounds to empty. + bounds.setEmpty(); + } return !bounds.isEmpty(); } @@ -3259,6 +3276,7 @@ public final class ViewRootImpl implements ViewParent, && mPendingContentInsets.equals(args.arg2) && mPendingStableInsets.equals(args.arg6) && mPendingVisibleInsets.equals(args.arg3) + && mPendingOutsets.equals(args.arg7) && args.arg4 == null) { break; } @@ -3277,6 +3295,7 @@ public final class ViewRootImpl implements ViewParent, mPendingContentInsets.set((Rect) args.arg2); mPendingStableInsets.set((Rect) args.arg6); mPendingVisibleInsets.set((Rect) args.arg3); + mPendingOutsets.set((Rect) args.arg7); args.recycle(); @@ -5387,7 +5406,7 @@ public final class ViewRootImpl implements ViewParent, (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets, - mPendingStableInsets, mPendingConfiguration, mSurface); + mPendingStableInsets, mPendingOutsets, mPendingConfiguration, mSurface); //Log.d(TAG, "<<<<<< BACK FROM relayout"); if (restore) { params.restore(); @@ -5656,7 +5675,8 @@ public final class ViewRootImpl implements ViewParent, } public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets, - Rect visibleInsets, Rect stableInsets, boolean reportDraw, Configuration newConfig) { + Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, + Configuration newConfig) { if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString() + " contentInsets=" + contentInsets.toShortString() + " visibleInsets=" + visibleInsets.toShortString() @@ -5676,6 +5696,7 @@ public final class ViewRootImpl implements ViewParent, args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig; args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets; args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets; + args.arg7 = sameProcessCall ? new Rect(outsets) : outsets; msg.obj = args; mHandler.sendMessage(msg); } @@ -6650,12 +6671,12 @@ public final class ViewRootImpl implements ViewParent, @Override public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, - Rect visibleInsets, Rect stableInsets, boolean reportDraw, + Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchResized(frame, overscanInsets, contentInsets, - visibleInsets, stableInsets, reportDraw, newConfig); + visibleInsets, stableInsets, outsets, reportDraw, newConfig); } } diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java index 5c8b023..886547a 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -145,13 +145,6 @@ public abstract class ViewStructure { public abstract void setText(CharSequence text, int selectionStart, int selectionEnd); /** - * Set default global style of the text previously set with - * {@link #setText}, derived from the given TextPaint object. Size, foreground color, - * background color, and style information will be extracted from the paint. - */ - public abstract void setTextPaint(TextPaint paint); - - /** * Explicitly set default global style information for text that was previously set with * {@link #setText}. * @@ -160,7 +153,7 @@ public abstract class ViewStructure { * @param bgColor The background color, packed as 0xAARRGGBB. * @param style Style flags, as defined by {@link android.app.AssistStructure.ViewNode}. */ - public abstract void setTextStyle(int size, int fgColor, int bgColor, int style); + public abstract void setTextStyle(float size, int fgColor, int bgColor, int style); /** * Set optional hint text associated with this view; this is for example the text that is diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index f0c86e5..45bc1df 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -309,6 +309,7 @@ public interface WindowManager extends ViewManager { * Window type: a above sub-panel on top of an application window and it's * sub-panel windows. These windows are displayed on top of their attached window * and any {@link #TYPE_APPLICATION_SUB_PANEL} panels. + * @hide */ public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5; diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index c16578e..606168c 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -20,6 +20,7 @@ import android.animation.ValueAnimator; import android.app.ActivityManager; import android.content.ComponentCallbacks2; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.content.res.Configuration; import android.os.IBinder; import android.os.RemoteException; @@ -247,7 +248,8 @@ public final class WindowManagerGlobal { // set from the application's hardware acceleration setting. final Context context = view.getContext(); if (context != null - && context.getApplicationInfo().hardwareAccelerated) { + && (context.getApplicationInfo().flags + & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) { wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } } diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index eebcd84..f7b6405 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -158,10 +158,12 @@ public interface WindowManagerPolicy { * @param decorFrame The decor frame specified by policy specific to this window, * to use for proper cropping during animation. * @param stableFrame The frame around which stable system decoration is positioned. + * @param outsetFrame The frame that includes areas that aren't part of the surface but we + * want to treat them as such. */ public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, - Rect stableFrame); + Rect stableFrame, Rect outsetFrame); /** * Retrieve the current frame of the window that has been assigned by @@ -945,17 +947,30 @@ public interface WindowManagerPolicy { public int focusChangedLw(WindowState lastFocus, WindowState newFocus); /** - * Called when the device is waking up. + * Called when the device has started waking up. */ - public void wakingUp(); + public void startedWakingUp(); /** - * Called when the device is going to sleep. + * Called when the device has finished waking up. + */ + public void finishedWakingUp(); + + /** + * Called when the device has started going to sleep. + * + * @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN}, + * or {@link #OFF_BECAUSE_OF_TIMEOUT}. + */ + public void startedGoingToSleep(int why); + + /** + * Called when the device has finished going to sleep. * - * @param why {@link #OFF_BECAUSE_OF_USER} or - * {@link #OFF_BECAUSE_OF_TIMEOUT}. + * @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN}, + * or {@link #OFF_BECAUSE_OF_TIMEOUT}. */ - public void goingToSleep(int why); + public void finishedGoingToSleep(int why); /** * Called when the device is about to turn on the screen to show content. diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 901a32d..b454d1c 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -2737,10 +2737,10 @@ public class AccessibilityNodeInfo implements Parcelable { if (mCollectionItemInfo != null) { parcel.writeInt(1); - parcel.writeInt(mCollectionItemInfo.getColumnIndex()); - parcel.writeInt(mCollectionItemInfo.getColumnSpan()); parcel.writeInt(mCollectionItemInfo.getRowIndex()); parcel.writeInt(mCollectionItemInfo.getRowSpan()); + parcel.writeInt(mCollectionItemInfo.getColumnIndex()); + parcel.writeInt(mCollectionItemInfo.getColumnSpan()); parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0); parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0); } else { diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index f61e372..5537b3e 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1320,6 +1320,22 @@ public final class InputMethodManager { } } + /** + * Call this when a view is being detached from a {@link android.view.Window}. + * @hide + */ + public void onViewDetachedFromWindow(View view) { + synchronized (mH) { + if (DEBUG) Log.v(TAG, "onViewDetachedFromWindow: " + view + + " mServedView=" + mServedView + + " hasWindowFocus=" + view.hasWindowFocus()); + if (mServedView == view && view.hasWindowFocus()) { + mNextServedView = null; + scheduleCheckFocusLocked(view); + } + } + } + static void scheduleCheckFocusLocked(View view) { ViewRootImpl viewRootImpl = view.getViewRootImpl(); if (viewRootImpl != null) { diff --git a/core/java/android/webkit/ViewAssistStructure.java b/core/java/android/webkit/ViewAssistStructure.java deleted file mode 100644 index bbaceee..0000000 --- a/core/java/android/webkit/ViewAssistStructure.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.webkit; - -import android.graphics.Rect; -import android.os.Bundle; -import android.text.TextPaint; -import android.view.ViewStructure; - - -/** - * TODO This class is temporary. It will be deleted once we update Webview APK to use the - * new ViewStructure method. - * @hide - */ -public class ViewAssistStructure extends android.view.ViewAssistStructure { - - private ViewStructure mV; - - public ViewAssistStructure(ViewStructure v) { - mV = v; - } - - @Override - public void setId(int id, String packageName, String typeName, String entryName) { - mV.setId(id, packageName, typeName, entryName); - } - - @Override - public void setDimens(int left, int top, int scrollX, int scrollY, int width, - int height) { - mV.setDimens(left, top, scrollX, scrollY, width, height); - } - - @Override - public void setVisibility(int visibility) { - mV.setVisibility(visibility); - } - - @Override - public void setAssistBlocked(boolean state) { - mV.setAssistBlocked(state); - } - - @Override - public void setEnabled(boolean state) { - mV.setEnabled(state); - } - - @Override - public void setClickable(boolean state) { - mV.setClickable(state); - } - - @Override - public void setLongClickable(boolean state) { - mV.setLongClickable(state); - } - - @Override - public void setStylusButtonPressable(boolean state) { - mV.setStylusButtonPressable(state); - } - - @Override - public void setFocusable(boolean state) { - mV.setFocusable(state); - } - - @Override - public void setFocused(boolean state) { - mV.setFocused(state); - } - - @Override - public void setAccessibilityFocused(boolean state) { - mV.setAccessibilityFocused(state); - } - - @Override - public void setCheckable(boolean state) { - mV.setCheckable(state); - } - - @Override - public void setChecked(boolean state) { - mV.setChecked(state); - } - - @Override - public void setSelected(boolean state) { - mV.setSelected(state); - } - - @Override - public void setActivated(boolean state) { - mV.setActivated(state); - } - - @Override - public void setClassName(String className) { - mV.setClassName(className); - } - - @Override - public void setContentDescription(CharSequence contentDescription) { - mV.setContentDescription(contentDescription); - } - - @Override - public void setText(CharSequence text) { - mV.setText(text); - } - - @Override - public void setText(CharSequence text, int selectionStart, int selectionEnd) { - mV.setText(text, selectionStart, selectionEnd); - } - - @Override - public void setTextPaint(TextPaint paint) { - mV.setTextPaint(paint); - } - - @Override - public void setTextStyle(int size, int fgColor, int bgColor, int style) { - mV.setTextStyle(size, fgColor, bgColor, style); - } - - @Override - public void setHint(CharSequence hint) { - mV.setHint(hint); - } - - @Override - public CharSequence getText() { - return mV.getText(); - } - - @Override - public int getTextSelectionStart() { - return mV.getTextSelectionStart(); - } - - @Override - public int getTextSelectionEnd() { - return mV.getTextSelectionEnd(); - } - - @Override - public CharSequence getHint() { - return mV.getHint(); - } - - @Override - public Bundle getExtras() { - return mV.getExtras(); - } - - @Override - public boolean hasExtras() { - return mV.hasExtras(); - } - - @Override - public void setChildCount(int num) { - mV.setChildCount(num); - } - - @Override - public int getChildCount() { - return mV.getChildCount(); - } - - @Override - public android.view.ViewAssistStructure newChild(int index) { - return mV.newChild(index); - } - - @Override - public android.view.ViewAssistStructure asyncNewChild(int index) { - return mV.asyncNewChild(index); - } - - @Override - public void asyncCommit() { - mV.asyncCommit(); - } - - @Override - public Rect getTempRect() { - return mV.getTempRect(); - } -} diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index ccb98b4..5080fcc 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -2436,8 +2436,7 @@ public class WebView extends AbsoluteLayout @Override public void onProvideVirtualStructure(ViewStructure structure) { - ViewAssistStructure s = new ViewAssistStructure(structure); - mProvider.getViewDelegate().onProvideVirtualAssistStructure(s); + mProvider.getViewDelegate().onProvideVirtualStructure(structure); } /** @hide */ diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java index 00aba2a..09afcf1 100644 --- a/core/java/android/webkit/WebViewProvider.java +++ b/core/java/android/webkit/WebViewProvider.java @@ -298,7 +298,7 @@ public interface WebViewProvider { interface ViewDelegate { public boolean shouldDelayChildPressedState(); - public void onProvideVirtualAssistStructure(android.view.ViewAssistStructure structure); + public void onProvideVirtualStructure(android.view.ViewStructure structure); public AccessibilityNodeProvider getAccessibilityNodeProvider(); diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index e963f53..a3332fa 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -820,44 +820,36 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mOwnerThread = Thread.currentThread(); final TypedArray a = context.obtainStyledAttributes( - attrs, com.android.internal.R.styleable.AbsListView, defStyleAttr, defStyleRes); + attrs, R.styleable.AbsListView, defStyleAttr, defStyleRes); - Drawable d = a.getDrawable(com.android.internal.R.styleable.AbsListView_listSelector); - if (d != null) { - setSelector(d); - } - - mDrawSelectorOnTop = a.getBoolean( - com.android.internal.R.styleable.AbsListView_drawSelectorOnTop, false); - - boolean stackFromBottom = a.getBoolean(R.styleable.AbsListView_stackFromBottom, false); - setStackFromBottom(stackFromBottom); - - boolean scrollingCacheEnabled = a.getBoolean(R.styleable.AbsListView_scrollingCache, true); - setScrollingCacheEnabled(scrollingCacheEnabled); - - boolean useTextFilter = a.getBoolean(R.styleable.AbsListView_textFilterEnabled, false); - setTextFilterEnabled(useTextFilter); - - int transcriptMode = a.getInt(R.styleable.AbsListView_transcriptMode, - TRANSCRIPT_MODE_DISABLED); - setTranscriptMode(transcriptMode); - - int color = a.getColor(R.styleable.AbsListView_cacheColorHint, 0); - setCacheColorHint(color); - - boolean enableFastScroll = a.getBoolean(R.styleable.AbsListView_fastScrollEnabled, false); - setFastScrollEnabled(enableFastScroll); - - int fastScrollStyle = a.getResourceId(R.styleable.AbsListView_fastScrollStyle, 0); - setFastScrollStyle(fastScrollStyle); - - boolean smoothScrollbar = a.getBoolean(R.styleable.AbsListView_smoothScrollbar, true); - setSmoothScrollbarEnabled(smoothScrollbar); - - setChoiceMode(a.getInt(R.styleable.AbsListView_choiceMode, CHOICE_MODE_NONE)); - setFastScrollAlwaysVisible( - a.getBoolean(R.styleable.AbsListView_fastScrollAlwaysVisible, false)); + final Drawable selector = a.getDrawable(R.styleable.AbsListView_listSelector); + if (selector != null) { + setSelector(selector); + } + + mDrawSelectorOnTop = a.getBoolean(R.styleable.AbsListView_drawSelectorOnTop, false); + + setStackFromBottom(a.getBoolean( + R.styleable.AbsListView_stackFromBottom, false)); + setScrollingCacheEnabled(a.getBoolean( + R.styleable.AbsListView_scrollingCache, true)); + setTextFilterEnabled(a.getBoolean( + R.styleable.AbsListView_textFilterEnabled, false)); + setTranscriptMode(a.getInt( + R.styleable.AbsListView_transcriptMode, TRANSCRIPT_MODE_DISABLED)); + setCacheColorHint(a.getColor( + R.styleable.AbsListView_cacheColorHint, 0)); + setSmoothScrollbarEnabled(a.getBoolean( + R.styleable.AbsListView_smoothScrollbar, true)); + setChoiceMode(a.getInt( + R.styleable.AbsListView_choiceMode, CHOICE_MODE_NONE)); + + setFastScrollEnabled(a.getBoolean( + R.styleable.AbsListView_fastScrollEnabled, false)); + setFastScrollStyle(a.getResourceId( + R.styleable.AbsListView_fastScrollStyle, 0)); + setFastScrollAlwaysVisible(a.getBoolean( + R.styleable.AbsListView_fastScrollAlwaysVisible, false)); a.recycle(); } diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index ff74c60..a4c8d1c 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -86,10 +86,10 @@ public abstract class AbsSeekBar extends ProgressBar { public AbsSeekBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - TypedArray a = context.obtainStyledAttributes( - attrs, com.android.internal.R.styleable.SeekBar, defStyleAttr, defStyleRes); + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.SeekBar, defStyleAttr, defStyleRes); - final Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb); + final Drawable thumb = a.getDrawable(R.styleable.SeekBar_thumb); setThumb(thumb); if (a.hasValue(R.styleable.SeekBar_thumbTintMode)) { @@ -103,18 +103,22 @@ public abstract class AbsSeekBar extends ProgressBar { mHasThumbTint = true; } + mSplitTrack = a.getBoolean(R.styleable.SeekBar_splitTrack, false); + // Guess thumb offset if thumb != null, but allow layout to override. - final int thumbOffset = a.getDimensionPixelOffset( - com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset()); + final int thumbOffset = a.getDimensionPixelOffset(R.styleable.SeekBar_thumbOffset, getThumbOffset()); setThumbOffset(thumbOffset); - mSplitTrack = a.getBoolean(com.android.internal.R.styleable.SeekBar_splitTrack, false); + final boolean useDisabledAlpha = a.getBoolean(R.styleable.SeekBar_useDisabledAlpha, true); a.recycle(); - a = context.obtainStyledAttributes(attrs, - com.android.internal.R.styleable.Theme, 0, 0); - mDisabledAlpha = a.getFloat(com.android.internal.R.styleable.Theme_disabledAlpha, 0.5f); - a.recycle(); + if (useDisabledAlpha) { + final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.Theme, 0, 0); + mDisabledAlpha = ta.getFloat(R.styleable.Theme_disabledAlpha, 0.5f); + ta.recycle(); + } else { + mDisabledAlpha = 1.0f; + } applyThumbTint(); @@ -360,7 +364,7 @@ public abstract class AbsSeekBar extends ProgressBar { super.drawableStateChanged(); final Drawable progressDrawable = getProgressDrawable(); - if (progressDrawable != null) { + if (progressDrawable != null && mDisabledAlpha < 1.0f) { progressDrawable.setAlpha(isEnabled() ? NO_ALPHA : (int) (NO_ALPHA * mDisabledAlpha)); } diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index 54e3996..6962711 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -304,16 +304,19 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { * called, false otherwise is returned. */ public boolean performItemClick(View view, int position, long id) { + final boolean result; if (mOnItemClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); mOnItemClickListener.onItemClick(this, view, position, id); - if (view != null) { - view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); - } - return true; + result = true; + } else { + result = false; } - return false; + if (view != null) { + view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); + } + return result; } /** diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index fc84cf9..0cac529 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -390,6 +390,7 @@ public class Editor { mPreserveDetachedSelection = true; hideControllers(); + stopSelectionActionMode(); mPreserveDetachedSelection = false; mTemporaryDetach = false; } @@ -624,7 +625,6 @@ public class Editor { mSuggestionsPopupWindow.hide(); } hideInsertionPointCursorController(); - stopSelectionActionMode(); } /** @@ -1101,10 +1101,12 @@ public class Editor { final int selStart = mTextView.getSelectionStart(); final int selEnd = mTextView.getSelectionEnd(); hideControllers(); + stopSelectionActionMode(); Selection.setSelection((Spannable) mTextView.getText(), selStart, selEnd); } else { if (mTemporaryDetach) mPreserveDetachedSelection = true; hideControllers(); + stopSelectionActionMode(); if (mTemporaryDetach) mPreserveDetachedSelection = false; downgradeEasyCorrectionSpans(); } @@ -1147,6 +1149,7 @@ public class Editor { // We do not hide the span controllers, since they can be added when a new text is // inserted into the text view (voice IME). hideCursorControllers(); + stopSelectionActionMode(); } private int getLastTapPosition() { @@ -1878,6 +1881,7 @@ public class Editor { void onTouchUpEvent(MotionEvent event) { boolean selectAllGotFocus = mSelectAllOnFocus && mTextView.didTouchFocusSelect(); hideControllers(); + stopSelectionActionMode(); CharSequence text = mTextView.getText(); if (!selectAllGotFocus && text.length() > 0) { // Move cursor @@ -1890,6 +1894,11 @@ public class Editor { if (!extractedTextModeWillBeStarted()) { if (isCursorInsideEasyCorrectionSpan()) { + // Cancel the single tap delayed runnable. + if (mSelectionModeWithoutSelectionRunnable != null) { + mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable); + } + mShowSuggestionRunnable = new Runnable() { public void run() { showSuggestions(); @@ -1993,6 +2002,7 @@ public class Editor { mSuggestionsPopupWindow = new SuggestionsPopupWindow(); } hideControllers(); + stopSelectionActionMode(); mSuggestionsPopupWindow.show(); } @@ -3110,35 +3120,30 @@ public class Editor { if (mTextView.canCut()) { menu.add(0, TextView.ID_CUT, 0, com.android.internal.R.string.cut). setAlphabeticShortcut('x'). - setShowAsAction( - MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT); + setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); } if (mTextView.canCopy()) { menu.add(0, TextView.ID_COPY, 0, com.android.internal.R.string.copy). setAlphabeticShortcut('c'). - setShowAsAction( - MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT); + setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); } if (mTextView.canPaste()) { menu.add(0, TextView.ID_PASTE, 0, com.android.internal.R.string.paste). setAlphabeticShortcut('v'). - setShowAsAction( - MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT); + setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); } if (mTextView.canShare()) { menu.add(0, TextView.ID_SHARE, 0, com.android.internal.R.string.share). - setShowAsAction( - MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT); + setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } if (mTextView.canSelectAllText()) { menu.add(0, TextView.ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll). setAlphabeticShortcut('a'). - setShowAsAction( - MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT); + setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } updateReplaceItem(menu); @@ -3152,8 +3157,7 @@ public class Editor { for (ResolveInfo info : supportedActivities) { menu.add(info.loadLabel(packageManager)) .setIntent(createProcessTextIntentForResolveInfo(info)) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM - | MenuItem.SHOW_AS_ACTION_WITH_TEXT); + .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } } } @@ -3185,8 +3189,7 @@ public class Editor { boolean replaceItemExists = menu.findItem(TextView.ID_REPLACE) != null; if (canReplace && !replaceItemExists) { menu.add(0, TextView.ID_REPLACE, 0, com.android.internal.R.string.replace). - setShowAsAction( - MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT); + setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } else if (!canReplace && replaceItemExists) { menu.removeItem(TextView.ID_REPLACE); } @@ -3819,13 +3822,15 @@ public class Editor { SystemClock.uptimeMillis() - TextView.sLastCutCopyOrTextChangedTime; // Cancel the single tap delayed runnable. - if (mDoubleTap && mSelectionModeWithoutSelectionRunnable != null) { + if (mSelectionModeWithoutSelectionRunnable != null + && (mDoubleTap || isCursorInsideEasyCorrectionSpan())) { 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 (!mDoubleTap && !isCursorInsideEasyCorrectionSpan() + && (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION)) { if (mSelectionModeWithoutSelectionRunnable == null) { mSelectionModeWithoutSelectionRunnable = new Runnable() { public void run() { diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 7dcaa1f..f8b965f 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -16,6 +16,7 @@ package android.widget; +import android.annotation.Nullable; import android.os.Bundle; import android.os.Trace; import com.android.internal.R; @@ -144,7 +145,7 @@ public class ListView extends AbsListView { } public ListView(Context context, AttributeSet attrs) { - this(context, attrs, com.android.internal.R.attr.listViewStyle); + this(context, attrs, R.attr.listViewStyle); } public ListView(Context context, AttributeSet attrs, int defStyleAttr) { @@ -155,38 +156,37 @@ public class ListView extends AbsListView { super(context, attrs, defStyleAttr, defStyleRes); final TypedArray a = context.obtainStyledAttributes( - attrs, com.android.internal.R.styleable.ListView, defStyleAttr, defStyleRes); + attrs, R.styleable.ListView, defStyleAttr, defStyleRes); - CharSequence[] entries = a.getTextArray( - com.android.internal.R.styleable.ListView_entries); + final CharSequence[] entries = a.getTextArray(R.styleable.ListView_entries); if (entries != null) { - setAdapter(new ArrayAdapter<CharSequence>(context, - com.android.internal.R.layout.simple_list_item_1, entries)); + setAdapter(new ArrayAdapter<>(context, R.layout.simple_list_item_1, entries)); } - final Drawable d = a.getDrawable(com.android.internal.R.styleable.ListView_divider); + final Drawable d = a.getDrawable(R.styleable.ListView_divider); if (d != null) { - // If a divider is specified use its intrinsic height for divider height + // Use an implicit divider height which may be explicitly + // overridden by android:dividerHeight further down. setDivider(d); } - - final Drawable osHeader = a.getDrawable( - com.android.internal.R.styleable.ListView_overScrollHeader); + + final Drawable osHeader = a.getDrawable(R.styleable.ListView_overScrollHeader); if (osHeader != null) { setOverscrollHeader(osHeader); } - final Drawable osFooter = a.getDrawable( - com.android.internal.R.styleable.ListView_overScrollFooter); + final Drawable osFooter = a.getDrawable(R.styleable.ListView_overScrollFooter); if (osFooter != null) { setOverscrollFooter(osFooter); } - // Use the height specified, zero being the default - final int dividerHeight = a.getDimensionPixelSize( - com.android.internal.R.styleable.ListView_dividerHeight, 0); - if (dividerHeight != 0) { - setDividerHeight(dividerHeight); + // Use an explicit divider height, if specified. + if (a.hasValueOrEmpty(R.styleable.ListView_dividerHeight)) { + final int dividerHeight = a.getDimensionPixelSize( + R.styleable.ListView_dividerHeight, 0); + if (dividerHeight != 0) { + setDividerHeight(dividerHeight); + } } mHeaderDividersEnabled = a.getBoolean(R.styleable.ListView_headerDividersEnabled, true); @@ -3434,18 +3434,23 @@ public class ListView extends AbsListView { * Returns the drawable that will be drawn between each item in the list. * * @return the current drawable drawn between list elements + * @attr ref R.styleable#ListView_divider */ + @Nullable public Drawable getDivider() { return mDivider; } /** - * Sets the drawable that will be drawn between each item in the list. If the drawable does - * not have an intrinsic height, you should also call {@link #setDividerHeight(int)} + * Sets the drawable that will be drawn between each item in the list. + * <p> + * <strong>Note:</strong> If the drawable does not have an intrinsic + * height, you should also call {@link #setDividerHeight(int)}. * - * @param divider The drawable to use. + * @param divider the drawable to use + * @attr ref R.styleable#ListView_divider */ - public void setDivider(Drawable divider) { + public void setDivider(@Nullable Drawable divider) { if (divider != null) { mDividerHeight = divider.getIntrinsicHeight(); } else { diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index dc75fd0..74843ee 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -867,13 +867,13 @@ public class RemoteViews implements Parcelable, Filter { if (targetDrawable != null) { // Perform modifications only if values are set correctly if (alpha != -1) { - targetDrawable.setAlpha(alpha); + targetDrawable.mutate().setAlpha(alpha); } if (filterMode != null) { - targetDrawable.setColorFilter(colorFilter, filterMode); + targetDrawable.mutate().setColorFilter(colorFilter, filterMode); } if (level != -1) { - targetDrawable.setLevel(level); + targetDrawable.mutate().setLevel(level); } } } diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 2709f25..ca57d1a 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -1704,12 +1704,26 @@ public class ScrollView extends FrameLayout { super.draw(canvas); if (mEdgeGlowTop != null) { final int scrollY = mScrollY; + final boolean clipToPadding = getClipToPadding(); if (!mEdgeGlowTop.isFinished()) { final int restoreCount = canvas.save(); - final int width = getWidth() - mPaddingLeft - mPaddingRight; - - canvas.translate(mPaddingLeft, Math.min(0, scrollY)); - mEdgeGlowTop.setSize(width, getHeight()); + final int width; + final int height; + final float translateX; + final float translateY; + if (clipToPadding) { + width = getWidth() - mPaddingLeft - mPaddingRight; + height = getHeight() - mPaddingTop - mPaddingBottom; + translateX = mPaddingLeft; + translateY = mPaddingTop; + } else { + width = getWidth(); + height = getHeight(); + translateX = 0; + translateY = 0; + } + canvas.translate(translateX, Math.min(0, scrollY) + translateY); + mEdgeGlowTop.setSize(width, height); if (mEdgeGlowTop.draw(canvas)) { postInvalidateOnAnimation(); } @@ -1717,11 +1731,23 @@ public class ScrollView extends FrameLayout { } if (!mEdgeGlowBottom.isFinished()) { final int restoreCount = canvas.save(); - final int width = getWidth() - mPaddingLeft - mPaddingRight; - final int height = getHeight(); - - canvas.translate(-width + mPaddingLeft, - Math.max(getScrollRange(), scrollY) + height); + final int width; + final int height; + final float translateX; + final float translateY; + if (clipToPadding) { + width = getWidth() - mPaddingLeft - mPaddingRight; + height = getHeight() - mPaddingTop - mPaddingBottom; + translateX = mPaddingLeft; + translateY = mPaddingTop; + } else { + width = getWidth(); + height = getHeight(); + translateX = 0; + translateY = 0; + } + canvas.translate(-width + translateX, + Math.max(getScrollRange(), scrollY) + height + translateY); canvas.rotate(180, width, 0); mEdgeGlowBottom.setSize(width, height); if (mEdgeGlowBottom.draw(canvas)) { diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index f42959f..49226cd 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -1374,7 +1374,9 @@ public class Switch extends CompoundButton { newText.append(oldText).append(' ').append(switchText); structure.setText(newText); } - structure.setTextPaint(mTextPaint); + // The style of the label text is provided via the base TextView class. This is more + // relevant than the style of the (optional) on/off text on the switch button itself, + // so ignore the size/color/style stored this.mTextPaint. } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index a93e7ef..e14e39c 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -25,6 +25,7 @@ import android.annotation.StringRes; import android.annotation.StyleRes; import android.annotation.XmlRes; import android.app.Activity; +import android.app.AssistStructure; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; @@ -6422,6 +6423,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // extracted mode will start. Some text is selected though, and will trigger an action mode // in the extracted view. mEditor.hideControllers(); + stopSelectionActionMode(); } /** @@ -8015,8 +8017,6 @@ 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(); @@ -8049,6 +8049,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * through a thunk. */ void handleTextChanged(CharSequence buffer, int start, int before, int after) { + sLastCutCopyOrTextChangedTime = 0; + final Editor.InputMethodState ims = mEditor == null ? null : mEditor.mInputMethodState; if (ims == null || ims.mBatchEditNesting == 0) { updateAfterEdit(); @@ -8256,6 +8258,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener super.onVisibilityChanged(changedView, visibility); if (mEditor != null && visibility != VISIBLE) { mEditor.hideControllers(); + stopSelectionActionMode(); } } @@ -8785,7 +8788,33 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final boolean isPassword = hasPasswordTransformationMethod(); if (!isPassword) { structure.setText(getText(), getSelectionStart(), getSelectionEnd()); - structure.setTextPaint(mTextPaint); + + // Extract style information that applies to the TextView as a whole. + int style = 0; + int typefaceStyle = getTypefaceStyle(); + if ((typefaceStyle & Typeface.BOLD) != 0) { + style |= AssistStructure.ViewNode.TEXT_STYLE_BOLD; + } + if ((typefaceStyle & Typeface.ITALIC) != 0) { + style |= AssistStructure.ViewNode.TEXT_STYLE_ITALIC; + } + + // Global styles can also be set via TextView.setPaintFlags(). + int paintFlags = mTextPaint.getFlags(); + if ((paintFlags & Paint.FAKE_BOLD_TEXT_FLAG) != 0) { + style |= AssistStructure.ViewNode.TEXT_STYLE_BOLD; + } + if ((paintFlags & Paint.UNDERLINE_TEXT_FLAG) != 0) { + style |= AssistStructure.ViewNode.TEXT_STYLE_UNDERLINE; + } + if ((paintFlags & Paint.STRIKE_THRU_TEXT_FLAG) != 0) { + style |= AssistStructure.ViewNode.TEXT_STYLE_STRIKE_THRU; + } + + // TextView does not have its own text background color. A background is either part + // of the View (and can be any drawable) or a BackgroundColorSpan inside the text. + structure.setTextStyle(getTextSize(), getCurrentTextColor(), + AssistStructure.ViewNode.TEXT_COLOR_UNDEFINED /* bgColor */, style); } structure.setHint(getHint()); } diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index ea18c12..c1ec6e6 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -659,11 +659,16 @@ public class ChooserActivity extends ResolverActivity { return super.getCount() + mServiceTargets.size() + mCallerTargets.size(); } - public int getCallerTargetsCount() { + @Override + public int getUnfilteredCount() { + return super.getUnfilteredCount() + mServiceTargets.size() + mCallerTargets.size(); + } + + public int getCallerTargetCount() { return mCallerTargets.size(); } - public int getServiceTargetsCount() { + public int getServiceTargetCount() { return mServiceTargets.size(); } @@ -696,6 +701,11 @@ public class ChooserActivity extends ResolverActivity { @Override public TargetInfo getItem(int position) { + return targetInfoForPosition(position, true); + } + + @Override + public TargetInfo targetInfoForPosition(int position, boolean filtered) { int offset = 0; final int callerTargetCount = mCallerTargets.size(); @@ -710,7 +720,8 @@ public class ChooserActivity extends ResolverActivity { } offset += serviceTargetCount; - return super.getItem(position - offset); + return filtered ? super.getItem(position - offset) + : getDisplayInfoAt(position - offset); } public void addServiceResults(DisplayResolveInfo origTarget, List<ChooserTarget> targets) { @@ -764,8 +775,8 @@ public class ChooserActivity extends ResolverActivity { @Override public int getCount() { return (int) ( - Math.ceil((float) mChooserListAdapter.getCallerTargetsCount() / mColumnCount) - + Math.ceil((float) mChooserListAdapter.getServiceTargetsCount() / mColumnCount) + Math.ceil((float) mChooserListAdapter.getCallerTargetCount() / mColumnCount) + + Math.ceil((float) mChooserListAdapter.getServiceTargetCount() / mColumnCount) + Math.ceil((float) mChooserListAdapter.getStandardTargetCount() / mColumnCount) ); } @@ -845,14 +856,14 @@ public class ChooserActivity extends ResolverActivity { } int getFirstRowPosition(int row) { - final int callerCount = mChooserListAdapter.getCallerTargetsCount(); + final int callerCount = mChooserListAdapter.getCallerTargetCount(); final int callerRows = (int) Math.ceil((float) callerCount / mColumnCount); if (row < callerRows) { return row * mColumnCount; } - final int serviceCount = mChooserListAdapter.getServiceTargetsCount(); + final int serviceCount = mChooserListAdapter.getServiceTargetCount(); final int serviceRows = (int) Math.ceil((float) serviceCount / mColumnCount); if (row < callerRows + serviceRows) { diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index 7c5c565..929cacd 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -34,6 +34,12 @@ interface IBatteryStats { void noteStopAudio(int uid); void noteResetVideo(); void noteResetAudio(); + void noteFlashlightOn(int uid); + void noteFlashlightOff(int uid); + void noteStartCamera(int uid); + void noteStopCamera(int uid); + void noteResetCamera(); + void noteResetFlashlight(); // Remaining methods are only used in Java. byte[] getStatistics(); @@ -72,8 +78,6 @@ interface IBatteryStats { void noteVibratorOn(int uid, long durationMillis); void noteVibratorOff(int uid); - void noteFlashlightOn(); - void noteFlashlightOff(); void noteStartGps(int uid); void noteStopGps(int uid); void noteScreenState(int state); diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 4696757..ba4af89 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -785,7 +785,7 @@ public class ResolverActivity extends Activity { } mAlwaysUseOption = alwaysUseOption; - int count = mAdapter.mDisplayList.size(); + int count = mAdapter.getUnfilteredCount(); if (count > 1 || (count == 1 && mAdapter.getOtherProfile() != null)) { setContentView(layoutId); mAdapterView = (AbsListView) findViewById(R.id.resolver_list); @@ -1392,6 +1392,18 @@ public class ResolverActivity extends Activity { return result; } + public int getUnfilteredCount() { + return mDisplayList.size(); + } + + public int getDisplayInfoCount() { + return mDisplayList.size(); + } + + public DisplayResolveInfo getDisplayInfoAt(int index) { + return mDisplayList.get(index); + } + public TargetInfo getItem(int position) { if (mFilterLastUsed && mLastChosenPosition >= 0 && position >= mLastChosenPosition) { position++; diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index eaca43b..62745d4 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -211,6 +211,8 @@ public final class BatteryStatsImpl extends BatteryStats { final SparseArray<ArrayList<StopwatchTimer>> mWifiBatchedScanTimers = new SparseArray<>(); final ArrayList<StopwatchTimer> mAudioTurnedOnTimers = new ArrayList<>(); final ArrayList<StopwatchTimer> mVideoTurnedOnTimers = new ArrayList<>(); + final ArrayList<StopwatchTimer> mFlashlightTurnedOnTimers = new ArrayList<>(); + final ArrayList<StopwatchTimer> mCameraTurnedOnTimers = new ArrayList<>(); // Last partial timers we use for distributing CPU usage. final ArrayList<StopwatchTimer> mLastPartialTimers = new ArrayList<>(); @@ -343,9 +345,12 @@ public final class BatteryStatsImpl extends BatteryStats { int mVideoOnNesting; StopwatchTimer mVideoOnTimer; - boolean mFlashlightOn; + int mFlashlightOnNesting; StopwatchTimer mFlashlightOnTimer; + int mCameraOnNesting; + StopwatchTimer mCameraOnTimer; + int mPhoneSignalStrengthBin = -1; int mPhoneSignalStrengthBinRaw = -1; final StopwatchTimer[] mPhoneSignalStrengthsTimer = @@ -3710,30 +3715,100 @@ public final class BatteryStatsImpl extends BatteryStats { getUidStatsLocked(uid).noteVibratorOffLocked(); } - public void noteFlashlightOnLocked() { - if (!mFlashlightOn) { - final long elapsedRealtime = SystemClock.elapsedRealtime(); - final long uptime = SystemClock.uptimeMillis(); + public void noteFlashlightOnLocked(int uid) { + uid = mapUid(uid); + final long elapsedRealtime = SystemClock.elapsedRealtime(); + final long uptime = SystemClock.uptimeMillis(); + if (mFlashlightOnNesting++ == 0) { mHistoryCur.states2 |= HistoryItem.STATE2_FLASHLIGHT_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight on to: " - + Integer.toHexString(mHistoryCur.states)); + + Integer.toHexString(mHistoryCur.states2)); addHistoryRecordLocked(elapsedRealtime, uptime); - mFlashlightOn = true; mFlashlightOnTimer.startRunningLocked(elapsedRealtime); } + getUidStatsLocked(uid).noteFlashlightTurnedOnLocked(elapsedRealtime); } - public void noteFlashlightOffLocked() { + public void noteFlashlightOffLocked(int uid) { + if (mFlashlightOnNesting == 0) { + return; + } + uid = mapUid(uid); final long elapsedRealtime = SystemClock.elapsedRealtime(); final long uptime = SystemClock.uptimeMillis(); - if (mFlashlightOn) { + if (--mFlashlightOnNesting == 0) { mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: " - + Integer.toHexString(mHistoryCur.states)); + + Integer.toHexString(mHistoryCur.states2)); addHistoryRecordLocked(elapsedRealtime, uptime); - mFlashlightOn = false; mFlashlightOnTimer.stopRunningLocked(elapsedRealtime); } + getUidStatsLocked(uid).noteFlashlightTurnedOffLocked(elapsedRealtime); + } + + public void noteCameraOnLocked(int uid) { + uid = mapUid(uid); + final long elapsedRealtime = SystemClock.elapsedRealtime(); + final long uptime = SystemClock.uptimeMillis(); + if (mCameraOnNesting++ == 0) { + mHistoryCur.states2 |= HistoryItem.STATE2_CAMERA_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Camera on to: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtime, uptime); + mCameraOnTimer.startRunningLocked(elapsedRealtime); + } + getUidStatsLocked(uid).noteCameraTurnedOnLocked(elapsedRealtime); + } + + public void noteCameraOffLocked(int uid) { + if (mCameraOnNesting == 0) { + return; + } + uid = mapUid(uid); + final long elapsedRealtime = SystemClock.elapsedRealtime(); + final long uptime = SystemClock.uptimeMillis(); + if (--mCameraOnNesting == 0) { + mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtime, uptime); + mCameraOnTimer.stopRunningLocked(elapsedRealtime); + } + getUidStatsLocked(uid).noteCameraTurnedOffLocked(elapsedRealtime); + } + + public void noteResetCameraLocked() { + if (mCameraOnNesting > 0) { + final long elapsedRealtime = SystemClock.elapsedRealtime(); + final long uptime = SystemClock.uptimeMillis(); + mCameraOnNesting = 0; + mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtime, uptime); + mCameraOnTimer.stopAllRunningLocked(elapsedRealtime); + for (int i=0; i<mUidStats.size(); i++) { + BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); + uid.noteResetCameraLocked(elapsedRealtime); + } + } + } + + public void noteResetFlashlightLocked() { + if (mFlashlightOnNesting > 0) { + final long elapsedRealtime = SystemClock.elapsedRealtime(); + final long uptime = SystemClock.uptimeMillis(); + mFlashlightOnNesting = 0; + mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG; + if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: " + + Integer.toHexString(mHistoryCur.states2)); + addHistoryRecordLocked(elapsedRealtime, uptime); + mFlashlightOnTimer.stopAllRunningLocked(elapsedRealtime); + for (int i=0; i<mUidStats.size(); i++) { + BatteryStatsImpl.Uid uid = mUidStats.valueAt(i); + uid.noteResetFlashlightLocked(elapsedRealtime); + } + } } public void noteWifiRadioPowerState(int powerState, long timestampNs) { @@ -4350,6 +4425,9 @@ public final class BatteryStatsImpl extends BatteryStats { StopwatchTimer mAudioTurnedOnTimer; StopwatchTimer mVideoTurnedOnTimer; + StopwatchTimer mFlashlightTurnedOnTimer; + StopwatchTimer mCameraTurnedOnTimer; + StopwatchTimer mForegroundActivityTimer; @@ -4650,6 +4728,54 @@ public final class BatteryStatsImpl extends BatteryStats { } } + public StopwatchTimer createFlashlightTurnedOnTimerLocked() { + if (mFlashlightTurnedOnTimer == null) { + mFlashlightTurnedOnTimer = new StopwatchTimer(Uid.this, FLASHLIGHT_TURNED_ON, + mFlashlightTurnedOnTimers, mOnBatteryTimeBase); + } + return mFlashlightTurnedOnTimer; + } + + public void noteFlashlightTurnedOnLocked(long elapsedRealtimeMs) { + createFlashlightTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs); + } + + public void noteFlashlightTurnedOffLocked(long elapsedRealtimeMs) { + if (mFlashlightTurnedOnTimer != null) { + mFlashlightTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs); + } + } + + public void noteResetFlashlightLocked(long elapsedRealtimeMs) { + if (mFlashlightTurnedOnTimer != null) { + mFlashlightTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs); + } + } + + public StopwatchTimer createCameraTurnedOnTimerLocked() { + if (mCameraTurnedOnTimer == null) { + mCameraTurnedOnTimer = new StopwatchTimer(Uid.this, CAMERA_TURNED_ON, + mCameraTurnedOnTimers, mOnBatteryTimeBase); + } + return mCameraTurnedOnTimer; + } + + public void noteCameraTurnedOnLocked(long elapsedRealtimeMs) { + createCameraTurnedOnTimerLocked().startRunningLocked(elapsedRealtimeMs); + } + + public void noteCameraTurnedOffLocked(long elapsedRealtimeMs) { + if (mCameraTurnedOnTimer != null) { + mCameraTurnedOnTimer.stopRunningLocked(elapsedRealtimeMs); + } + } + + public void noteResetCameraLocked(long elapsedRealtimeMs) { + if (mCameraTurnedOnTimer != null) { + mCameraTurnedOnTimer.stopAllRunningLocked(elapsedRealtimeMs); + } + } + public StopwatchTimer createForegroundActivityTimerLocked() { if (mForegroundActivityTimer == null) { mForegroundActivityTimer = new StopwatchTimer( @@ -4762,19 +4888,23 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override - public long getAudioTurnedOnTime(long elapsedRealtimeUs, int which) { - if (mAudioTurnedOnTimer == null) { - return 0; - } - return mAudioTurnedOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which); + public Timer getAudioTurnedOnTimer() { + return mAudioTurnedOnTimer; } @Override - public long getVideoTurnedOnTime(long elapsedRealtimeUs, int which) { - if (mVideoTurnedOnTimer == null) { - return 0; - } - return mVideoTurnedOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which); + public Timer getVideoTurnedOnTimer() { + return mVideoTurnedOnTimer; + } + + @Override + public Timer getFlashlightTurnedOnTimer() { + return mFlashlightTurnedOnTimer; + } + + @Override + public Timer getCameraTurnedOnTimer() { + return mCameraTurnedOnTimer; } @Override @@ -4994,6 +5124,12 @@ public final class BatteryStatsImpl extends BatteryStats { if (mVideoTurnedOnTimer != null) { active |= !mVideoTurnedOnTimer.reset(false); } + if (mFlashlightTurnedOnTimer != null) { + active |= !mFlashlightTurnedOnTimer.reset(false); + } + if (mCameraTurnedOnTimer != null) { + active |= !mCameraTurnedOnTimer.reset(false); + } if (mForegroundActivityTimer != null) { active |= !mForegroundActivityTimer.reset(false); } @@ -5155,6 +5291,14 @@ public final class BatteryStatsImpl extends BatteryStats { mVideoTurnedOnTimer.detach(); mVideoTurnedOnTimer = null; } + if (mFlashlightTurnedOnTimer != null) { + mFlashlightTurnedOnTimer.detach(); + mFlashlightTurnedOnTimer = null; + } + if (mCameraTurnedOnTimer != null) { + mCameraTurnedOnTimer.detach(); + mCameraTurnedOnTimer = null; + } if (mForegroundActivityTimer != null) { mForegroundActivityTimer.detach(); mForegroundActivityTimer = null; @@ -5291,6 +5435,18 @@ public final class BatteryStatsImpl extends BatteryStats { } else { out.writeInt(0); } + if (mFlashlightTurnedOnTimer != null) { + out.writeInt(1); + mFlashlightTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs); + } else { + out.writeInt(0); + } + if (mCameraTurnedOnTimer != null) { + out.writeInt(1); + mCameraTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs); + } else { + out.writeInt(0); + } if (mForegroundActivityTimer != null) { out.writeInt(1); mForegroundActivityTimer.writeToParcel(out, elapsedRealtimeUs); @@ -5469,6 +5625,18 @@ public final class BatteryStatsImpl extends BatteryStats { mVideoTurnedOnTimer = null; } if (in.readInt() != 0) { + mFlashlightTurnedOnTimer = new StopwatchTimer(Uid.this, FLASHLIGHT_TURNED_ON, + mFlashlightTurnedOnTimers, mOnBatteryTimeBase, in); + } else { + mFlashlightTurnedOnTimer = null; + } + if (in.readInt() != 0) { + mCameraTurnedOnTimer = new StopwatchTimer(Uid.this, CAMERA_TURNED_ON, + mCameraTurnedOnTimers, mOnBatteryTimeBase, in); + } else { + mCameraTurnedOnTimer = null; + } + if (in.readInt() != 0) { mForegroundActivityTimer = new StopwatchTimer( Uid.this, FOREGROUND_ACTIVITY, null, mOnBatteryTimeBase, in); } else { @@ -6700,6 +6868,7 @@ public final class BatteryStatsImpl extends BatteryStats { mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase); mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase); mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase); + mCameraOnTimer = new StopwatchTimer(null, -13, null, mOnBatteryTimeBase); mOnBattery = mOnBatteryInternal = false; long uptime = SystemClock.uptimeMillis() * 1000; long realtime = SystemClock.elapsedRealtime() * 1000; @@ -7285,6 +7454,7 @@ public final class BatteryStatsImpl extends BatteryStats { mAudioOnTimer.reset(false); mVideoOnTimer.reset(false); mFlashlightOnTimer.reset(false); + mCameraOnTimer.reset(false); for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) { mPhoneSignalStrengthsTimer[i].reset(false); } @@ -8811,8 +8981,10 @@ public final class BatteryStatsImpl extends BatteryStats { } mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt(); - mFlashlightOn = false; + mFlashlightOnNesting = 0; mFlashlightOnTimer.readSummaryFromParcelLocked(in); + mCameraOnNesting = 0; + mCameraOnTimer.readSummaryFromParcelLocked(in); int NKW = in.readInt(); if (NKW > 10000) { @@ -8883,6 +9055,12 @@ public final class BatteryStatsImpl extends BatteryStats { u.createVideoTurnedOnTimerLocked().readSummaryFromParcelLocked(in); } if (in.readInt() != 0) { + u.createFlashlightTurnedOnTimerLocked().readSummaryFromParcelLocked(in); + } + if (in.readInt() != 0) { + u.createCameraTurnedOnTimerLocked().readSummaryFromParcelLocked(in); + } + if (in.readInt() != 0) { u.createForegroundActivityTimerLocked().readSummaryFromParcelLocked(in); } u.mProcessState = Uid.PROCESS_STATE_NONE; @@ -9132,6 +9310,7 @@ public final class BatteryStatsImpl extends BatteryStats { } out.writeInt(mNumConnectivityChange); mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); + mCameraOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); out.writeInt(mKernelWakelockStats.size()); for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) { @@ -9208,6 +9387,18 @@ public final class BatteryStatsImpl extends BatteryStats { } else { out.writeInt(0); } + if (u.mFlashlightTurnedOnTimer != null) { + out.writeInt(1); + u.mFlashlightTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); + } else { + out.writeInt(0); + } + if (u.mCameraTurnedOnTimer != null) { + out.writeInt(1); + u.mCameraTurnedOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); + } else { + out.writeInt(0); + } if (u.mForegroundActivityTimer != null) { out.writeInt(1); u.mForegroundActivityTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); @@ -9453,8 +9644,10 @@ public final class BatteryStatsImpl extends BatteryStats { mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase); mVideoOnNesting = 0; mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase); - mFlashlightOn = false; + mFlashlightOnNesting = 0; mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase, in); + mCameraOnNesting = 0; + mCameraOnTimer = new StopwatchTimer(null, -13, null, mOnBatteryTimeBase, in); mDischargeUnplugLevel = in.readInt(); mDischargePlugLevel = in.readInt(); mDischargeCurrentLevel = in.readInt(); @@ -9499,6 +9692,8 @@ public final class BatteryStatsImpl extends BatteryStats { mWifiMulticastTimers.clear(); mAudioTurnedOnTimers.clear(); mVideoTurnedOnTimers.clear(); + mFlashlightTurnedOnTimers.clear(); + mCameraTurnedOnTimers.clear(); sNumSpeedSteps = in.readInt(); @@ -9598,6 +9793,7 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(mLoadedNumConnectivityChange); out.writeInt(mUnpluggedNumConnectivityChange); mFlashlightOnTimer.writeToParcel(out, uSecRealtime); + mCameraOnTimer.writeToParcel(out, uSecRealtime); out.writeInt(mDischargeUnplugLevel); out.writeInt(mDischargePlugLevel); out.writeInt(mDischargeCurrentLevel); @@ -9732,6 +9928,8 @@ public final class BatteryStatsImpl extends BatteryStats { } pr.println("*** Flashlight timer:"); mFlashlightOnTimer.logState(pr, " "); + pr.println("*** Camera timer:"); + mCameraOnTimer.logState(pr, " "); } super.dumpLocked(context, pw, flags, reqUid, histStart); } diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java index c977997..b0d24fd 100644 --- a/core/java/com/android/internal/os/SomeArgs.java +++ b/core/java/com/android/internal/os/SomeArgs.java @@ -46,6 +46,7 @@ public final class SomeArgs { public Object arg4; public Object arg5; public Object arg6; + public Object arg7; public int argi1; public int argi2; public int argi3; @@ -97,6 +98,7 @@ public final class SomeArgs { arg4 = null; arg5 = null; arg6 = null; + arg7 = null; argi1 = 0; argi2 = 0; argi3 = 0; diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl index f93b1a1..7ab4651 100644 --- a/core/java/com/android/internal/policy/IKeyguardService.aidl +++ b/core/java/com/android/internal/policy/IKeyguardService.aidl @@ -22,6 +22,7 @@ import com.android.internal.policy.IKeyguardExitCallback; import android.os.Bundle; oneway interface IKeyguardService { + /** * Sets the Keyguard as occluded when a window dismisses the Keyguard with flag * FLAG_SHOW_ON_LOCK_SCREEN. @@ -36,8 +37,27 @@ oneway interface IKeyguardService { void dismiss(); void onDreamingStarted(); void onDreamingStopped(); - void onScreenTurnedOff(int reason); - void onScreenTurnedOn(IKeyguardShowCallback callback); + + /** + * Called when the device has started going to sleep. + * + * @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN}, + * or {@link #OFF_BECAUSE_OF_TIMEOUT}. + */ + void onStartedGoingToSleep(int reason); + + /** + * Called when the device has finished going to sleep. + * + * @param why {@link #OFF_BECAUSE_OF_USER}, {@link #OFF_BECAUSE_OF_ADMIN}, + * or {@link #OFF_BECAUSE_OF_TIMEOUT}. + */ + void onFinishedGoingToSleep(int reason); + + /** + * Called when the device has started waking up. + */ + void onStartedWakingUp(IKeyguardShowCallback callback); void setKeyguardEnabled(boolean enabled); void onSystemReady(); void doKeyguardTimeout(in Bundle options); diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index bc64373..22c0680 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -56,7 +56,6 @@ import android.view.Window; import android.view.WindowInsets; import android.view.WindowManager; import com.android.internal.R; -import com.android.internal.util.ScreenShapeHelper; import com.android.internal.view.FloatingActionMode; import com.android.internal.view.RootViewSurfaceTaker; import com.android.internal.view.StandaloneActionMode; @@ -156,7 +155,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { TypedValue mFixedWidthMinor; TypedValue mFixedHeightMajor; TypedValue mFixedHeightMinor; - int mOutsetBottomPx; // This is the top-level view of the window, containing the window decor. private DecorView mDecor; @@ -289,6 +287,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private Boolean mSharedElementsUseOverlay; private Rect mTempRect; + private Rect mOutsets = new Rect(); static class WindowManagerHolder { static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface( @@ -2220,12 +2219,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private final ColorViewState mStatusColorViewState = new ColorViewState( SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS, Gravity.TOP, + Gravity.LEFT, STATUS_BAR_BACKGROUND_TRANSITION_NAME, com.android.internal.R.id.statusBarBackground, FLAG_FULLSCREEN); private final ColorViewState mNavigationColorViewState = new ColorViewState( SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION, Gravity.BOTTOM, + Gravity.RIGHT, NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME, com.android.internal.R.id.navigationBarBackground, 0 /* hideWindowFlag */); @@ -2241,6 +2242,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private int mLastRightInset = 0; private boolean mLastHasTopStableInset = false; private boolean mLastHasBottomStableInset = false; + private boolean mLastHasRightStableInset = false; private int mLastWindowFlags = 0; private int mRootScrollY = 0; @@ -2401,19 +2403,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override - public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { - if (mOutsetBottomPx != 0) { - WindowInsets newInsets = insets.replaceSystemWindowInsets( - insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), - insets.getSystemWindowInsetRight(), mOutsetBottomPx); - return super.dispatchApplyWindowInsets(newInsets); - } else { - return super.dispatchApplyWindowInsets(insets); - } - } - - - @Override public boolean onTouchEvent(MotionEvent event) { return onInterceptTouchEvent(event); } @@ -2624,11 +2613,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } - if (mOutsetBottomPx != 0) { + getOutsets(mOutsets); + if (mOutsets.top > 0 || mOutsets.bottom > 0) { int mode = MeasureSpec.getMode(heightMeasureSpec); if (mode != MeasureSpec.UNSPECIFIED) { int height = MeasureSpec.getSize(heightMeasureSpec); - heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + mOutsetBottomPx, mode); + heightMeasureSpec = MeasureSpec.makeMeasureSpec( + height + mOutsets.top + mOutsets.bottom, mode); + } + } + if (mOutsets.left > 0 || mOutsets.right > 0) { + int mode = MeasureSpec.getMode(widthMeasureSpec); + if (mode != MeasureSpec.UNSPECIFIED) { + int width = MeasureSpec.getSize(widthMeasureSpec); + widthMeasureSpec = MeasureSpec.makeMeasureSpec( + width + mOutsets.left + mOutsets.right, mode); } } @@ -2666,6 +2665,18 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + getOutsets(mOutsets); + if (mOutsets.left > 0) { + offsetLeftAndRight(-mOutsets.left); + } + if (mOutsets.top > 0) { + offsetTopAndBottom(-mOutsets.top); + } + } + + @Override public void draw(Canvas canvas) { super.draw(canvas); @@ -2674,7 +2685,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } - @Override public boolean showContextMenuForChild(View originalView) { // Reuse the context menu builder @@ -2875,12 +2885,19 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { boolean hasBottomStableInset = insets.getStableInsetBottom() != 0; disallowAnimate |= (hasBottomStableInset != mLastHasBottomStableInset); mLastHasBottomStableInset = hasBottomStableInset; + + boolean hasRightStableInset = insets.getStableInsetRight() != 0; + disallowAnimate |= (hasRightStableInset != mLastHasRightStableInset); + mLastHasRightStableInset = hasRightStableInset; } updateColorViewInt(mStatusColorViewState, sysUiVisibility, mStatusBarColor, - mLastTopInset, animate && !disallowAnimate); + mLastTopInset, false /* matchVertical */, animate && !disallowAnimate); + + boolean navBarToRightEdge = mLastBottomInset == 0 && mLastRightInset > 0; + int navBarSize = navBarToRightEdge ? mLastRightInset : mLastBottomInset; updateColorViewInt(mNavigationColorViewState, sysUiVisibility, mNavigationBarColor, - mLastBottomInset, animate && !disallowAnimate); + navBarSize, navBarToRightEdge, animate && !disallowAnimate); } // When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, we still need @@ -2924,9 +2941,20 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return insets; } + /** + * Update a color view + * + * @param state the color view to update. + * @param sysUiVis the current systemUiVisibility to apply. + * @param color the current color to apply. + * @param size the current size in the non-parent-matching dimension. + * @param verticalBar if true the view is attached to a vertical edge, otherwise to a + * horizontal edge, + * @param animate if true, the change will be animated. + */ private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color, - int height, boolean animate) { - boolean show = height > 0 && (sysUiVis & state.systemUiHideFlag) == 0 + int size, boolean verticalBar, boolean animate) { + boolean show = size > 0 && (sysUiVis & state.systemUiHideFlag) == 0 && (getAttributes().flags & state.hideWindowFlag) == 0 && (getAttributes().flags & state.translucentFlag) == 0 && (color & Color.BLACK) != 0 @@ -2935,6 +2963,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { boolean visibilityChanged = false; View view = state.view; + int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size; + int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT; + int resolvedGravity = verticalBar ? state.horizontalGravity : state.verticalGravity; + if (view == null) { if (show) { state.view = view = new View(mContext); @@ -2945,8 +2977,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { view.setVisibility(INVISIBLE); state.targetVisibility = VISIBLE; - addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, height, - Gravity.START | state.verticalGravity)); + addView(view, new LayoutParams(resolvedWidth, resolvedHeight, resolvedGravity)); updateColorViewTranslations(); } } else { @@ -2955,8 +2986,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { state.targetVisibility = vis; if (show) { LayoutParams lp = (LayoutParams) view.getLayoutParams(); - if (lp.height != height) { - lp.height = height; + if (lp.height != resolvedHeight || lp.width != resolvedWidth + || lp.gravity != resolvedGravity) { + lp.height = resolvedHeight; + lp.width = resolvedWidth; + lp.gravity = resolvedGravity; view.setLayoutParams(lp); } view.setBackgroundColor(color); @@ -3583,19 +3617,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { requestFeature(FEATURE_ACTIVITY_TRANSITIONS); } - final WindowManager windowService = (WindowManager) getContext().getSystemService( - Context.WINDOW_SERVICE); - if (windowService != null) { - final Display display = windowService.getDefaultDisplay(); - final boolean shouldUseBottomOutset = - display.getDisplayId() == Display.DEFAULT_DISPLAY - || (getForcedWindowFlags() & FLAG_FULLSCREEN) != 0; - if (shouldUseBottomOutset) { - mOutsetBottomPx = ScreenShapeHelper.getWindowOutsetBottomPx( - getContext().getResources().getDisplayMetrics(), a); - } - } - final Context context = getContext(); final int targetSdk = context.getApplicationInfo().targetSdkVersion; final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB; @@ -4884,16 +4905,18 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { final int systemUiHideFlag; final int translucentFlag; final int verticalGravity; + final int horizontalGravity; final String transitionName; final int hideWindowFlag; ColorViewState(int systemUiHideFlag, - int translucentFlag, int verticalGravity, + int translucentFlag, int verticalGravity, int horizontalGravity, String transitionName, int id, int hideWindowFlag) { this.id = id; this.systemUiHideFlag = systemUiHideFlag; this.translucentFlag = translucentFlag; this.verticalGravity = verticalGravity; + this.horizontalGravity = horizontalGravity; this.transitionName = transitionName; this.hideWindowFlag = hideWindowFlag; } diff --git a/core/java/com/android/internal/util/ScreenShapeHelper.java b/core/java/com/android/internal/util/ScreenShapeHelper.java index 58ae853..4a196f8 100644 --- a/core/java/com/android/internal/util/ScreenShapeHelper.java +++ b/core/java/com/android/internal/util/ScreenShapeHelper.java @@ -18,19 +18,13 @@ public class ScreenShapeHelper { /** * Return the bottom pixel window outset of a window given its style attributes. - * @param displayMetrics Display metrics of the current device - * @param windowStyle Window style attributes for the window. * @return An outset dimension in pixels or 0 if no outset should be applied. */ - public static int getWindowOutsetBottomPx(DisplayMetrics displayMetrics, - TypedArray windowStyle) { + public static int getWindowOutsetBottomPx(Resources resources) { if (IS_EMULATOR) { return SystemProperties.getInt(ViewRootImpl.PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX, 0); - } else if (windowStyle.hasValue(R.styleable.Window_windowOutsetBottom)) { - TypedValue outsetBottom = new TypedValue(); - windowStyle.getValue(R.styleable.Window_windowOutsetBottom, outsetBottom); - return (int) outsetBottom.getDimension(displayMetrics); + } else { + return resources.getInteger(com.android.internal.R.integer.config_windowOutsetBottom); } - return 0; } } diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java index e27ba13..3eeabcd 100644 --- a/core/java/com/android/internal/view/BaseIWindow.java +++ b/core/java/com/android/internal/view/BaseIWindow.java @@ -34,8 +34,8 @@ public class BaseIWindow extends IWindow.Stub { } @Override - public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, - Rect visibleInsets, Rect stableInsets, boolean reportDraw, Configuration newConfig) { + public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, + Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig) { if (reportDraw) { try { mSession.finishDrawing(this); diff --git a/core/java/com/android/internal/widget/ButtonBarLayout.java b/core/java/com/android/internal/widget/ButtonBarLayout.java index f58ab03..39613e8 100644 --- a/core/java/com/android/internal/widget/ButtonBarLayout.java +++ b/core/java/com/android/internal/widget/ButtonBarLayout.java @@ -33,9 +33,6 @@ public class ButtonBarLayout extends LinearLayout { /** Whether the current configuration allows stacking. */ private final boolean mAllowStacking; - /** Whether the layout is currently stacked. */ - private boolean mStacked; - private int mLastWidthSize = -1; public ButtonBarLayout(Context context, AttributeSet attrs) { @@ -44,15 +41,14 @@ public class ButtonBarLayout extends LinearLayout { final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ButtonBarLayout); mAllowStacking = ta.getBoolean(R.styleable.ButtonBarLayout_allowStacking, false); ta.recycle(); - - mStacked = getOrientation() == VERTICAL; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int widthSize = MeasureSpec.getSize(widthMeasureSpec); + if (mAllowStacking) { - final int widthSize = MeasureSpec.getSize(widthMeasureSpec); - if (widthSize > mLastWidthSize && mStacked) { + if (widthSize > mLastWidthSize && isStacked()) { // We're being measured wider this time, try un-stacking. setStacked(false); } @@ -60,18 +56,37 @@ public class ButtonBarLayout extends LinearLayout { mLastWidthSize = widthSize; } - super.onMeasure(widthMeasureSpec, heightMeasureSpec); + boolean needsRemeasure = false; + + // If we're not stacked, make sure the measure spec is AT_MOST rather + // than EXACTLY. This ensures that we'll still get TOO_SMALL so that we + // know to stack the buttons. + final int initialWidthMeasureSpec; + if (!isStacked() && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) { + initialWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST); + + // We'll need to remeasure again to fill excess space. + needsRemeasure = true; + } else { + initialWidthMeasureSpec = widthMeasureSpec; + } + + super.onMeasure(initialWidthMeasureSpec, heightMeasureSpec); - if (mAllowStacking && !mStacked) { + if (mAllowStacking && !isStacked()) { final int measuredWidth = getMeasuredWidthAndState(); final int measuredWidthState = measuredWidth & MEASURED_STATE_MASK; if (measuredWidthState == MEASURED_STATE_TOO_SMALL) { setStacked(true); // Measure again in the new orientation. - super.onMeasure(widthMeasureSpec, heightMeasureSpec); + needsRemeasure = true; } } + + if (needsRemeasure) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } } private void setStacked(boolean stacked) { @@ -89,7 +104,9 @@ public class ButtonBarLayout extends LinearLayout { for (int i = childCount - 2; i >= 0; i--) { bringChildToFront(getChildAt(i)); } + } - mStacked = stacked; + private boolean isStacked() { + return getOrientation() == LinearLayout.VERTICAL; } } diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index 3cff59a..1fc0ac3 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -353,10 +353,14 @@ public final class FloatingToolbar { * from. */ public FloatingToolbarPopup(View parent) { + mMarginHorizontal = parent.getResources() + .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin); + mMarginVertical = parent.getResources() + .getDimensionPixelSize(R.dimen.floating_toolbar_vertical_margin); mParent = Preconditions.checkNotNull(parent); mContentContainer = createContentContainer(parent.getContext()); mPopupWindow = createPopupWindow(mContentContainer); - mShowAnimation = createGrowFadeInFromBottom(mContentContainer); + mShowAnimation = createGrowFadeInFromBottom(mContentContainer, mMarginHorizontal); mDismissAnimation = createShrinkFadeOutFromBottomAnimation( mContentContainer, 150, // startDelay @@ -376,17 +380,15 @@ public final class FloatingToolbar { mPopupWindow.dismiss(); } }); - mMarginHorizontal = parent.getResources() - .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin); - mMarginVertical = parent.getResources() - .getDimensionPixelSize(R.dimen.floating_toolbar_vertical_margin); } /** * Lays out buttons for the specified menu items. */ - public void layoutMenuItems(List<MenuItem> menuItems, - MenuItem.OnMenuItemClickListener menuItemClickListener, int suggestedWidth) { + public void layoutMenuItems( + List<MenuItem> menuItems, + MenuItem.OnMenuItemClickListener menuItemClickListener, + int suggestedWidth) { Preconditions.checkNotNull(menuItems); mContentContainer.removeAllViews(); @@ -593,7 +595,9 @@ public final class FloatingToolbar { final int startWidth = mContentContainer.getWidth(); final int startHeight = mContentContainer.getHeight(); final float startY = mContentContainer.getY(); - final float right = mContentContainer.getX() + mContentContainer.getWidth(); + final float left = mContentContainer.getX(); + final float right = left + mContentContainer.getWidth(); + final boolean rtl = mContentContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; Animation widthAnimation = new Animation() { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { @@ -601,7 +605,11 @@ public final class FloatingToolbar { int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth)); params.width = startWidth + deltaWidth; mContentContainer.setLayoutParams(params); - mContentContainer.setX(right - mContentContainer.getWidth()); + if (rtl) { + mContentContainer.setX(left); + } else { + mContentContainer.setX(right - mContentContainer.getWidth()); + } } }; Animation heightAnimation = new Animation() { @@ -644,9 +652,11 @@ public final class FloatingToolbar { final int targetHeight = mainPanelSize.getHeight(); final int startWidth = mContentContainer.getWidth(); final int startHeight = mContentContainer.getHeight(); - final float right = mContentContainer.getX() + mContentContainer.getWidth(); final float bottom = mContentContainer.getY() + mContentContainer.getHeight(); final boolean morphedUpwards = (mOverflowDirection == OVERFLOW_DIRECTION_UP); + final float left = mContentContainer.getX(); + final float right = left + mContentContainer.getWidth(); + final boolean rtl = mContentContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; Animation widthAnimation = new Animation() { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { @@ -654,7 +664,11 @@ public final class FloatingToolbar { int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth)); params.width = startWidth + deltaWidth; mContentContainer.setLayoutParams(params); - mContentContainer.setX(right - mContentContainer.getWidth()); + if (rtl) { + mContentContainer.setX(left); + } else { + mContentContainer.setX(right - mContentContainer.getWidth()); + } } }; Animation heightAnimation = new Animation() { @@ -747,9 +761,7 @@ public final class FloatingToolbar { */ private void positionMainPanel() { Preconditions.checkNotNull(mMainPanel); - float x = mPopupWindow.getWidth() - - (mMainPanel.getView().getMeasuredWidth() + mMarginHorizontal); - mContentContainer.setX(x); + mContentContainer.setX(mMarginHorizontal); float y = mMarginVertical; if (mOverflowDirection == OVERFLOW_DIRECTION_UP) { @@ -1320,12 +1332,14 @@ public final class FloatingToolbar { * * @param view The view to animate */ - private static AnimatorSet createGrowFadeInFromBottom(View view) { + private static AnimatorSet createGrowFadeInFromBottom(View view, int x) { AnimatorSet growFadeInFromBottomAnimation = new AnimatorSet(); growFadeInFromBottomAnimation.playTogether( ObjectAnimator.ofFloat(view, View.SCALE_X, 0.5f, 1).setDuration(125), ObjectAnimator.ofFloat(view, View.SCALE_Y, 0.5f, 1).setDuration(125), - ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(75)); + ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(75), + // Make sure that view.x is always fixed throughout the duration of this animation. + ObjectAnimator.ofFloat(view, View.X, x, x)); growFadeInFromBottomAnimation.setStartDelay(50); return growFadeInFromBottomAnimation; } diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index bfafff6..dfb7c50 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -16,6 +16,8 @@ package com.android.internal.widget; +import com.android.internal.widget.VerifyCredentialResponse; + /** {@hide} */ interface ILockSettings { void setBoolean(in String key, in boolean value, in int userId); @@ -25,11 +27,11 @@ interface ILockSettings { long getLong(in String key, in long defaultValue, in int userId); String getString(in String key, in String defaultValue, in int userId); void setLockPattern(in String pattern, in String savedPattern, int userId); - boolean checkPattern(in String pattern, int userId); - byte[] verifyPattern(in String pattern, long challenge, int userId); + VerifyCredentialResponse checkPattern(in String pattern, int userId); + VerifyCredentialResponse verifyPattern(in String pattern, long challenge, int userId); void setLockPassword(in String password, in String savedPassword, int userId); - boolean checkPassword(in String password, int userId); - byte[] verifyPassword(in String password, long challenge, int userId); + VerifyCredentialResponse checkPassword(in String password, int userId); + VerifyCredentialResponse verifyPassword(in String password, long challenge, int userId); boolean checkVoldPassword(int userId); boolean havePattern(int userId); boolean havePassword(int userId); diff --git a/core/java/com/android/internal/widget/LockPatternChecker.java b/core/java/com/android/internal/widget/LockPatternChecker.java index ac0f5fe..4880664 100644 --- a/core/java/com/android/internal/widget/LockPatternChecker.java +++ b/core/java/com/android/internal/widget/LockPatternChecker.java @@ -2,6 +2,8 @@ package com.android.internal.widget; import android.os.AsyncTask; +import com.android.internal.widget.LockPatternUtils.RequestThrottledException; + import java.util.List; /** @@ -16,8 +18,10 @@ public final class LockPatternChecker { * Invoked when a security check is finished. * * @param matched Whether the PIN/Password/Pattern matches the stored one. + * @param throttleTimeoutMs The amount of time in ms to wait before reattempting + * the call. Only non-0 if matched is false. */ - void onChecked(boolean matched); + void onChecked(boolean matched, int throttleTimeoutMs); } /** @@ -28,8 +32,10 @@ public final class LockPatternChecker { * Invoked when a security verification is finished. * * @param attestation The attestation that the challenge was verified, or null. + * @param throttleTimeoutMs The amount of time in ms to wait before reattempting + * the call. Only non-0 if attestation is null. */ - void onVerified(byte[] attestation); + void onVerified(byte[] attestation, int throttleTimeoutMs); } /** @@ -47,14 +53,21 @@ public final class LockPatternChecker { final int userId, final OnVerifyCallback callback) { AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() { + private int mThrottleTimeout; + @Override protected byte[] doInBackground(Void... args) { - return utils.verifyPattern(pattern, challenge, userId); + try { + return utils.verifyPattern(pattern, challenge, userId); + } catch (RequestThrottledException ex) { + mThrottleTimeout = ex.getTimeoutMs(); + return null; + } } @Override protected void onPostExecute(byte[] result) { - callback.onVerified(result); + callback.onVerified(result, mThrottleTimeout); } }; task.execute(); @@ -74,14 +87,21 @@ public final class LockPatternChecker { final int userId, final OnCheckCallback callback) { AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() { + private int mThrottleTimeout; + @Override protected Boolean doInBackground(Void... args) { - return utils.checkPattern(pattern, userId); + try { + return utils.checkPattern(pattern, userId); + } catch (RequestThrottledException ex) { + mThrottleTimeout = ex.getTimeoutMs(); + return false; + } } @Override protected void onPostExecute(Boolean result) { - callback.onChecked(result); + callback.onChecked(result, mThrottleTimeout); } }; task.execute(); @@ -103,14 +123,21 @@ public final class LockPatternChecker { final int userId, final OnVerifyCallback callback) { AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() { + private int mThrottleTimeout; + @Override protected byte[] doInBackground(Void... args) { - return utils.verifyPassword(password, challenge, userId); + try { + return utils.verifyPassword(password, challenge, userId); + } catch (RequestThrottledException ex) { + mThrottleTimeout = ex.getTimeoutMs(); + return null; + } } @Override protected void onPostExecute(byte[] result) { - callback.onVerified(result); + callback.onVerified(result, mThrottleTimeout); } }; task.execute(); @@ -130,14 +157,21 @@ public final class LockPatternChecker { final int userId, final OnCheckCallback callback) { AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() { + private int mThrottleTimeout; + @Override protected Boolean doInBackground(Void... args) { - return utils.checkPassword(password, userId); + try { + return utils.checkPassword(password, userId); + } catch (RequestThrottledException ex) { + mThrottleTimeout = ex.getTimeoutMs(); + return false; + } } @Override protected void onPostExecute(Boolean result) { - callback.onChecked(result); + callback.onChecked(result, mThrottleTimeout); } }; task.execute(); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 55b058c..aee0ff6 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -60,24 +60,12 @@ public class LockPatternUtils { private static final boolean DEBUG = false; /** - * The maximum number of incorrect attempts before the user is prevented - * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}. - */ - public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5; - - /** * The number of incorrect attempts before which we fall back on an alternative * method of verifying the user, and resetting their lock pattern. */ public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20; /** - * How long the user is prevented from trying again after entering the - * wrong pattern too many times. - */ - public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L; - - /** * The interval of the countdown for showing progress of the lockout. */ public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L; @@ -109,6 +97,7 @@ public class LockPatternUtils { @Deprecated public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently"; public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline"; + public final static String LOCKOUT_ATTEMPT_TIMEOUT_MS = "lockscreen.lockoutattempttimeoutmss"; public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen"; public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type"; @Deprecated @@ -144,6 +133,23 @@ public class LockPatternUtils { private DevicePolicyManager mDevicePolicyManager; private ILockSettings mLockSettingsService; + + public static final class RequestThrottledException extends Exception { + private int mTimeoutMs; + public RequestThrottledException(int timeoutMs) { + mTimeoutMs = timeoutMs; + } + + /** + * @return The amount of time in ms before another request may + * be executed + */ + public int getTimeoutMs() { + return mTimeoutMs; + } + + } + public DevicePolicyManager getDevicePolicyManager() { if (mDevicePolicyManager == null) { mDevicePolicyManager = @@ -239,9 +245,23 @@ public class LockPatternUtils { * @param challenge The challenge to verify against the pattern * @return the attestation that the challenge was verified, or null. */ - public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId) { + public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId) + throws RequestThrottledException { try { - return getLockSettings().verifyPattern(patternToString(pattern), challenge, userId); + VerifyCredentialResponse response = + getLockSettings().verifyPattern(patternToString(pattern), challenge, userId); + if (response == null) { + // Shouldn't happen + return null; + } + + if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { + return response.getPayload(); + } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { + throw new RequestThrottledException(response.getTimeout()); + } else { + return null; + } } catch (RemoteException re) { return null; } @@ -253,9 +273,19 @@ public class LockPatternUtils { * @param pattern The pattern to check. * @return Whether the pattern matches the stored one. */ - public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId) { + public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId) + throws RequestThrottledException { try { - return getLockSettings().checkPattern(patternToString(pattern), userId); + VerifyCredentialResponse response = + getLockSettings().checkPattern(patternToString(pattern), userId); + + if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { + return true; + } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { + throw new RequestThrottledException(response.getTimeout()); + } else { + return false; + } } catch (RemoteException re) { return true; } @@ -270,9 +300,19 @@ public class LockPatternUtils { * @param challenge The challenge to verify against the password * @return the attestation that the challenge was verified, or null. */ - public byte[] verifyPassword(String password, long challenge, int userId) { + public byte[] verifyPassword(String password, long challenge, int userId) + throws RequestThrottledException { try { - return getLockSettings().verifyPassword(password, challenge, userId); + VerifyCredentialResponse response = + getLockSettings().verifyPassword(password, challenge, userId); + + if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { + return response.getPayload(); + } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { + throw new RequestThrottledException(response.getTimeout()); + } else { + return null; + } } catch (RemoteException re) { return null; } @@ -284,9 +324,17 @@ public class LockPatternUtils { * @param password The password to check. * @return Whether the password matches the stored one. */ - public boolean checkPassword(String password, int userId) { + public boolean checkPassword(String password, int userId) throws RequestThrottledException { try { - return getLockSettings().checkPassword(password, userId); + VerifyCredentialResponse response = + getLockSettings().checkPassword(password, userId); + if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { + return true; + } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { + throw new RequestThrottledException(response.getTimeout()); + } else { + return false; + } } catch (RemoteException re) { return true; } @@ -992,9 +1040,10 @@ public class LockPatternUtils { * pattern until the deadline has passed. * @return the chosen deadline. */ - public long setLockoutAttemptDeadline(int userId) { - final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS; + public long setLockoutAttemptDeadline(int userId, int timeoutMs) { + final long deadline = SystemClock.elapsedRealtime() + timeoutMs; setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId); + setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, timeoutMs, userId); return deadline; } @@ -1005,8 +1054,9 @@ public class LockPatternUtils { */ public long getLockoutAttemptDeadline(int userId) { final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId); + final long timeoutMs = getLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0L, userId); final long now = SystemClock.elapsedRealtime(); - if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) { + if (deadline < now || deadline > (now + timeoutMs)) { return 0L; } return deadline; diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java index 6d4e058..35ed63b 100644 --- a/core/java/com/android/internal/widget/SwipeDismissLayout.java +++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java @@ -16,9 +16,11 @@ package com.android.internal.widget; -import android.animation.TimeInterpolator; import android.app.Activity; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.Log; @@ -28,8 +30,6 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewTreeObserver; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; /** @@ -62,10 +62,6 @@ public class SwipeDismissLayout extends FrameLayout { // Cached ViewConfiguration and system-wide constant values private int mSlop; private int mMinFlingVelocity; - private int mMaxFlingVelocity; - private long mAnimationTime; - private TimeInterpolator mCancelInterpolator; - private TimeInterpolator mDismissInterpolator; // Transient properties private int mActiveTouchId; @@ -92,6 +88,18 @@ public class SwipeDismissLayout extends FrameLayout { } } }; + private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mDismissed) { + dismiss(); + } else { + cancel(); + } + resetMembers(); + } + }; + private IntentFilter mScreenOffFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF); private float mLastX; @@ -114,11 +122,6 @@ public class SwipeDismissLayout extends FrameLayout { ViewConfiguration vc = ViewConfiguration.get(context); mSlop = vc.getScaledTouchSlop(); mMinFlingVelocity = vc.getScaledMinimumFlingVelocity(); - mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); - mAnimationTime = getContext().getResources().getInteger( - android.R.integer.config_shortAnimTime); - mCancelInterpolator = new DecelerateInterpolator(1.5f); - mDismissInterpolator = new AccelerateInterpolator(1.5f); TypedArray a = context.getTheme().obtainStyledAttributes( com.android.internal.R.styleable.Theme); mUseDynamicTranslucency = !a.hasValue( @@ -141,15 +144,17 @@ public class SwipeDismissLayout extends FrameLayout { getViewTreeObserver().addOnEnterAnimationCompleteListener( mOnEnterAnimationCompleteListener); } + getContext().registerReceiver(mScreenOffReceiver, mScreenOffFilter); } @Override protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); + getContext().unregisterReceiver(mScreenOffReceiver); if (getContext() instanceof Activity) { getViewTreeObserver().removeOnEnterAnimationCompleteListener( mOnEnterAnimationCompleteListener); } + super.onDetachedFromWindow(); } @Override diff --git a/core/java/com/android/internal/widget/VerifyCredentialResponse.aidl b/core/java/com/android/internal/widget/VerifyCredentialResponse.aidl new file mode 100644 index 0000000..59a4bba --- /dev/null +++ b/core/java/com/android/internal/widget/VerifyCredentialResponse.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +/** + * Response object for an ILockSettings verification request. + * @hide + */ +parcelable VerifyCredentialResponse; + diff --git a/core/java/com/android/internal/widget/VerifyCredentialResponse.java b/core/java/com/android/internal/widget/VerifyCredentialResponse.java new file mode 100644 index 0000000..48109ca --- /dev/null +++ b/core/java/com/android/internal/widget/VerifyCredentialResponse.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Response object for a ILockSettings credential verification request. + * @hide + */ +public final class VerifyCredentialResponse implements Parcelable { + + public static final int RESPONSE_ERROR = -1; + public static final int RESPONSE_OK = 0; + public static final int RESPONSE_RETRY = 1; + + public static final VerifyCredentialResponse OK = new VerifyCredentialResponse(); + public static final VerifyCredentialResponse ERROR + = new VerifyCredentialResponse(RESPONSE_ERROR, 0, null); + + private int mResponseCode; + private byte[] mPayload; + private int mTimeout; + + public static final Parcelable.Creator<VerifyCredentialResponse> CREATOR + = new Parcelable.Creator<VerifyCredentialResponse>() { + @Override + public VerifyCredentialResponse createFromParcel(Parcel source) { + int responseCode = source.readInt(); + VerifyCredentialResponse response = new VerifyCredentialResponse(responseCode, 0, null); + if (responseCode == RESPONSE_RETRY) { + response.setTimeout(source.readInt()); + } else if (responseCode == RESPONSE_OK) { + int size = source.readInt(); + if (size > 0) { + byte[] payload = new byte[size]; + source.readByteArray(payload); + response.setPayload(payload); + } + } + return response; + } + + @Override + public VerifyCredentialResponse[] newArray(int size) { + return new VerifyCredentialResponse[size]; + } + + }; + + public VerifyCredentialResponse() { + mResponseCode = RESPONSE_OK; + mPayload = null; + } + + + public VerifyCredentialResponse(byte[] payload) { + mPayload = payload; + mResponseCode = RESPONSE_OK; + } + + public VerifyCredentialResponse(int timeout) { + mTimeout = timeout; + mResponseCode = RESPONSE_RETRY; + mPayload = null; + } + + private VerifyCredentialResponse(int responseCode, int timeout, byte[] payload) { + mResponseCode = responseCode; + mTimeout = timeout; + mPayload = payload; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mResponseCode); + if (mResponseCode == RESPONSE_RETRY) { + dest.writeInt(mTimeout); + } else if (mResponseCode == RESPONSE_OK) { + if (mPayload != null) { + dest.writeInt(mPayload.length); + dest.writeByteArray(mPayload); + } + } + } + + @Override + public int describeContents() { + return 0; + } + + public byte[] getPayload() { + return mPayload; + } + + public int getTimeout() { + return mTimeout; + } + + public int getResponseCode() { + return mResponseCode; + } + + private void setTimeout(int timeout) { + mTimeout = timeout; + } + + private void setPayload(byte[] payload) { + mPayload = payload; + } +} |