diff options
57 files changed, 1109 insertions, 198 deletions
diff --git a/Android.mk b/Android.mk index 452d72c1e28d..84cad4e268f7 100644 --- a/Android.mk +++ b/Android.mk @@ -559,6 +559,7 @@ aidl_files := \ frameworks/base/core/java/android/app/PendingIntent.aidl \ frameworks/base/core/java/android/app/AlarmManager.aidl \ frameworks/base/core/java/android/app/SearchableInfo.aidl \ + frameworks/base/core/java/android/app/VoiceInteractor.aidl \ frameworks/base/core/java/android/app/job/JobParameters.aidl \ frameworks/base/core/java/android/app/job/JobInfo.aidl \ frameworks/base/core/java/android/appwidget/AppWidgetProviderInfo.aidl \ diff --git a/api/current.txt b/api/current.txt index c05254a7c86a..7bac613a5c56 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5355,8 +5355,25 @@ package android.app { method public void onConfirmationResult(boolean, android.os.Bundle); } + public static class VoiceInteractor.PickOptionRequest extends android.app.VoiceInteractor.Request { + ctor public VoiceInteractor.PickOptionRequest(java.lang.CharSequence, android.app.VoiceInteractor.PickOptionRequest.Option[], android.os.Bundle); + method public void onPickOptionResult(boolean, android.app.VoiceInteractor.PickOptionRequest.Option[], android.os.Bundle); + } + + public static final class VoiceInteractor.PickOptionRequest.Option implements android.os.Parcelable { + ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence); + method public android.app.VoiceInteractor.PickOptionRequest.Option addSynonym(java.lang.CharSequence); + method public int countSynonyms(); + method public int describeContents(); + method public android.os.Bundle getExtras(); + method public java.lang.CharSequence getLabel(); + method public java.lang.CharSequence getSynonymAt(int); + method public void setExtras(android.os.Bundle); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.app.VoiceInteractor.PickOptionRequest.Option> CREATOR; + } + public static abstract class VoiceInteractor.Request { - ctor public VoiceInteractor.Request(); method public void cancel(); method public android.app.Activity getActivity(); method public android.content.Context getContext(); @@ -17315,6 +17332,7 @@ package android.media.tv { method public int describeContents(); method public final int getAudioChannelCount(); method public final int getAudioSampleRate(); + method public final java.lang.String getDescription(); method public final android.os.Bundle getExtra(); method public final java.lang.String getId(); method public final java.lang.String getLanguage(); @@ -17334,6 +17352,7 @@ package android.media.tv { method public android.media.tv.TvTrackInfo build(); method public final android.media.tv.TvTrackInfo.Builder setAudioChannelCount(int); method public final android.media.tv.TvTrackInfo.Builder setAudioSampleRate(int); + method public final android.media.tv.TvTrackInfo.Builder setDescription(java.lang.String); method public final android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle); method public final android.media.tv.TvTrackInfo.Builder setLanguage(java.lang.String); method public final android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float); @@ -27895,10 +27914,12 @@ package android.service.voice { method public boolean onKeyLongPress(int, android.view.KeyEvent); method public boolean onKeyMultiple(int, int, android.view.KeyEvent); method public boolean onKeyUp(int, android.view.KeyEvent); + method public abstract void onPickOption(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.app.VoiceInteractor.PickOptionRequest.Option[], android.os.Bundle); method public void onShow(android.os.Bundle, int); method public void onTaskFinished(android.content.Intent, int); method public void onTaskStarted(android.content.Intent, int); method public void setContentView(android.view.View); + method public void setKeepAwake(boolean); method public void setTheme(int); method public void show(); method public void showWindow(); @@ -27924,6 +27945,7 @@ package android.service.voice { method public void sendCommandResult(boolean, android.os.Bundle); method public void sendCompleteVoiceResult(android.os.Bundle); method public void sendConfirmResult(boolean, android.os.Bundle); + method public void sendPickOptionResult(boolean, android.app.VoiceInteractor.PickOptionRequest.Option[], android.os.Bundle); } public abstract class VoiceInteractionSessionService extends android.app.Service { diff --git a/api/system-current.txt b/api/system-current.txt index 538820723e30..89c0460e9883 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5445,8 +5445,25 @@ package android.app { method public void onConfirmationResult(boolean, android.os.Bundle); } + public static class VoiceInteractor.PickOptionRequest extends android.app.VoiceInteractor.Request { + ctor public VoiceInteractor.PickOptionRequest(java.lang.CharSequence, android.app.VoiceInteractor.PickOptionRequest.Option[], android.os.Bundle); + method public void onPickOptionResult(boolean, android.app.VoiceInteractor.PickOptionRequest.Option[], android.os.Bundle); + } + + public static final class VoiceInteractor.PickOptionRequest.Option implements android.os.Parcelable { + ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence); + method public android.app.VoiceInteractor.PickOptionRequest.Option addSynonym(java.lang.CharSequence); + method public int countSynonyms(); + method public int describeContents(); + method public android.os.Bundle getExtras(); + method public java.lang.CharSequence getLabel(); + method public java.lang.CharSequence getSynonymAt(int); + method public void setExtras(android.os.Bundle); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.app.VoiceInteractor.PickOptionRequest.Option> CREATOR; + } + public static abstract class VoiceInteractor.Request { - ctor public VoiceInteractor.Request(); method public void cancel(); method public android.app.Activity getActivity(); method public android.content.Context getContext(); @@ -18734,6 +18751,7 @@ package android.media.tv { method public int describeContents(); method public final int getAudioChannelCount(); method public final int getAudioSampleRate(); + method public final java.lang.String getDescription(); method public final android.os.Bundle getExtra(); method public final java.lang.String getId(); method public final java.lang.String getLanguage(); @@ -18753,6 +18771,7 @@ package android.media.tv { method public android.media.tv.TvTrackInfo build(); method public final android.media.tv.TvTrackInfo.Builder setAudioChannelCount(int); method public final android.media.tv.TvTrackInfo.Builder setAudioSampleRate(int); + method public final android.media.tv.TvTrackInfo.Builder setDescription(java.lang.String); method public final android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle); method public final android.media.tv.TvTrackInfo.Builder setLanguage(java.lang.String); method public final android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float); @@ -29779,10 +29798,12 @@ package android.service.voice { method public boolean onKeyLongPress(int, android.view.KeyEvent); method public boolean onKeyMultiple(int, int, android.view.KeyEvent); method public boolean onKeyUp(int, android.view.KeyEvent); + method public abstract void onPickOption(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.app.VoiceInteractor.PickOptionRequest.Option[], android.os.Bundle); method public void onShow(android.os.Bundle, int); method public void onTaskFinished(android.content.Intent, int); method public void onTaskStarted(android.content.Intent, int); method public void setContentView(android.view.View); + method public void setKeepAwake(boolean); method public void setTheme(int); method public void show(); method public void showWindow(); @@ -29808,6 +29829,7 @@ package android.service.voice { method public void sendCommandResult(boolean, android.os.Bundle); method public void sendCompleteVoiceResult(android.os.Bundle); method public void sendConfirmResult(boolean, android.os.Bundle); + method public void sendPickOptionResult(boolean, android.app.VoiceInteractor.PickOptionRequest.Option[], android.os.Bundle); } public abstract class VoiceInteractionSessionService extends android.app.Service { diff --git a/core/java/android/annotation/TransitionRes.java b/core/java/android/annotation/TransitionRes.java new file mode 100644 index 000000000000..06bac74984a5 --- /dev/null +++ b/core/java/android/annotation/TransitionRes.java @@ -0,0 +1,37 @@ +/* + * 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.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +/** + * Denotes that an integer parameter, field or method return value is expected + * to be a transition resource reference. + * + * {@hide} + */ +@Documented +@Retention(SOURCE) +@Target({METHOD, PARAMETER, FIELD}) +public @interface TransitionRes { +} diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 997f69dc0f81..1484af8aa691 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2440,6 +2440,16 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } + + case SET_VOICE_KEEP_AWAKE_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IVoiceInteractionSession session = IVoiceInteractionSession.Stub.asInterface( + data.readStrongBinder()); + boolean keepAwake = data.readInt() != 0; + setVoiceKeepAwake(session, keepAwake); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -5658,5 +5668,19 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + @Override + public void setVoiceKeepAwake(IVoiceInteractionSession session, boolean keepAwake) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(session.asBinder()); + data.writeInt(keepAwake ? 1 : 0); + mRemote.transact(SET_VOICE_KEEP_AWAKE_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + private IBinder mRemote; } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 3dcbdd229288..d794aa3a37de 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -485,6 +485,9 @@ public interface IActivityManager extends IInterface { public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException; public void dumpHeapFinished(String path) throws RemoteException; + public void setVoiceKeepAwake(IVoiceInteractionSession session, boolean keepAwake) + throws RemoteException; + /* * Private non-Binder interfaces */ @@ -818,4 +821,5 @@ public interface IActivityManager extends IInterface { int GET_LOCK_TASK_MODE_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+286; int SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+287; int DUMP_HEAP_FINISHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+288; + int SET_VOICE_KEEP_AWAKE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+289; } diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 8abe22325904..79797c947171 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -27,6 +27,7 @@ import android.content.res.ResourcesKey; import android.hardware.display.DisplayManagerGlobal; import android.util.ArrayMap; import android.util.DisplayMetrics; +import android.util.Log; import android.util.Pair; import android.util.Slog; import android.view.Display; @@ -164,7 +165,7 @@ public class ResourcesManager { WeakReference<Resources> wr = mActiveResources.get(key); r = wr != null ? wr.get() : null; - //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate()); + //if (r != null) Log.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate()); if (r != null && r.getAssets().isUpToDate()) { if (DEBUG) Slog.w(TAG, "Returning cached resources " + r + " " + resDir + ": appScale=" + r.getCompatibilityInfo().applicationScale @@ -174,7 +175,7 @@ public class ResourcesManager { } //if (r != null) { - // Slog.w(TAG, "Throwing away out-of-date resources!!!! " + // Log.w(TAG, "Throwing away out-of-date resources!!!! " // + r + " " + resDir); //} @@ -204,14 +205,18 @@ public class ResourcesManager { if (libDirs != null) { for (String libDir : libDirs) { - if (assets.addAssetPath(libDir) == 0) { - Slog.w(TAG, "Asset path '" + libDir + - "' does not exist or contains no resources."); + if (libDir.endsWith(".apk")) { + // Avoid opening files we know do not have resources, + // like code-only .jar files. + if (assets.addAssetPath(libDir) == 0) { + Log.w(TAG, "Asset path '" + libDir + + "' does not exist or contains no resources."); + } } } } - //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics); + //Log.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics); DisplayMetrics dm = getDisplayMetricsLocked(displayId); Configuration config; final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); diff --git a/core/java/android/app/VoiceInteractor.aidl b/core/java/android/app/VoiceInteractor.aidl new file mode 100644 index 000000000000..40a4a0e9be1a --- /dev/null +++ b/core/java/android/app/VoiceInteractor.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +parcelable VoiceInteractor.PickOptionRequest.Option; diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java index 7b84cb4c82ff..da7bb05f4862 100644 --- a/core/java/android/app/VoiceInteractor.java +++ b/core/java/android/app/VoiceInteractor.java @@ -21,6 +21,8 @@ import android.os.Bundle; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.Parcel; +import android.os.Parcelable; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; @@ -69,6 +71,7 @@ public class VoiceInteractor { public void executeMessage(Message msg) { SomeArgs args = (SomeArgs)msg.obj; Request request; + boolean complete; switch (msg.what) { case MSG_CONFIRMATION_RESULT: request = pullRequest((IVoiceInteractorRequest)args.arg1, true); @@ -81,13 +84,28 @@ public class VoiceInteractor { request.clear(); } break; + case MSG_PICK_OPTION_RESULT: + complete = msg.arg1 != 0; + request = pullRequest((IVoiceInteractorRequest)args.arg1, complete); + if (DEBUG) Log.d(TAG, "onPickOptionResult: req=" + + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request + + " finished=" + complete + " selection=" + args.arg2 + + " result=" + args.arg3); + if (request != null) { + ((PickOptionRequest)request).onPickOptionResult(complete, + (PickOptionRequest.Option[]) args.arg2, (Bundle) args.arg3); + if (complete) { + request.clear(); + } + } + break; case MSG_COMPLETE_VOICE_RESULT: request = pullRequest((IVoiceInteractorRequest)args.arg1, true); if (DEBUG) Log.d(TAG, "onCompleteVoice: req=" + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request + " result=" + args.arg1); if (request != null) { - ((CompleteVoiceRequest)request).onCompleteResult((Bundle) args.arg2); + ((CompleteVoiceRequest)request).onCompleteResult((Bundle) args.arg1); request.clear(); } break; @@ -95,21 +113,22 @@ public class VoiceInteractor { request = pullRequest((IVoiceInteractorRequest)args.arg1, true); if (DEBUG) Log.d(TAG, "onAbortVoice: req=" + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request - + " result=" + args.arg1); + + " result=" + args.arg2); if (request != null) { ((AbortVoiceRequest)request).onAbortResult((Bundle) args.arg2); request.clear(); } break; case MSG_COMMAND_RESULT: - request = pullRequest((IVoiceInteractorRequest)args.arg1, msg.arg1 != 0); + complete = msg.arg1 != 0; + request = pullRequest((IVoiceInteractorRequest)args.arg1, complete); if (DEBUG) Log.d(TAG, "onCommandResult: req=" + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request + " completed=" + msg.arg1 + " result=" + args.arg2); if (request != null) { ((CommandRequest)request).onCommandResult(msg.arg1 != 0, (Bundle) args.arg2); - if (msg.arg1 != 0) { + if (complete) { request.clear(); } } @@ -129,10 +148,17 @@ public class VoiceInteractor { final IVoiceInteractorCallback.Stub mCallback = new IVoiceInteractorCallback.Stub() { @Override - public void deliverConfirmationResult(IVoiceInteractorRequest request, boolean confirmed, + public void deliverConfirmationResult(IVoiceInteractorRequest request, boolean finished, Bundle result) { mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO( - MSG_CONFIRMATION_RESULT, confirmed ? 1 : 0, request, result)); + MSG_CONFIRMATION_RESULT, finished ? 1 : 0, request, result)); + } + + @Override + public void deliverPickOptionResult(IVoiceInteractorRequest request, + boolean finished, PickOptionRequest.Option[] options, Bundle result) { + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOOO( + MSG_PICK_OPTION_RESULT, finished ? 1 : 0, request, options, result)); } @Override @@ -164,17 +190,22 @@ public class VoiceInteractor { final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>(); static final int MSG_CONFIRMATION_RESULT = 1; - static final int MSG_COMPLETE_VOICE_RESULT = 2; - static final int MSG_ABORT_VOICE_RESULT = 3; - static final int MSG_COMMAND_RESULT = 4; - static final int MSG_CANCEL_RESULT = 5; + static final int MSG_PICK_OPTION_RESULT = 2; + static final int MSG_COMPLETE_VOICE_RESULT = 3; + static final int MSG_ABORT_VOICE_RESULT = 4; + static final int MSG_COMMAND_RESULT = 5; + static final int MSG_CANCEL_RESULT = 6; + /** + * Base class for voice interaction requests that can be submitted to the interactor. + * Do not instantiate this directly -- instead, use the appropriate subclass. + */ public static abstract class Request { IVoiceInteractorRequest mRequestInterface; Context mContext; Activity mActivity; - public Request() { + Request() { } public void cancel() { @@ -212,22 +243,25 @@ public class VoiceInteractor { String packageName, IVoiceInteractorCallback callback) throws RemoteException; } + /** + * Confirms an operation with the user via the trusted system + * VoiceInteractionService. This allows an Activity to complete an unsafe operation that + * would require the user to touch the screen when voice interaction mode is not enabled. + * The result of the confirmation will be returned through an asynchronous call to + * either {@link #onConfirmationResult(boolean, android.os.Bundle)} or + * {@link #onCancel()}. + * + * <p>In some cases this may be a simple yes / no confirmation or the confirmation could + * include context information about how the action will be completed + * (e.g. booking a cab might include details about how long until the cab arrives) + * so the user can give a confirmation. + */ public static class ConfirmationRequest extends Request { final CharSequence mPrompt; final Bundle mExtras; /** - * Confirms an operation with the user via the trusted system - * VoiceInteractionService. This allows an Activity to complete an unsafe operation that - * would require the user to touch the screen when voice interaction mode is not enabled. - * The result of the confirmation will be returned through an asynchronous call to - * either {@link #onConfirmationResult(boolean, android.os.Bundle)} or - * {@link #onCancel()}. - * - * <p>In some cases this may be a simple yes / no confirmation or the confirmation could - * include context information about how the action will be completed - * (e.g. booking a cab might include details about how long until the cab arrives) - * so the user can give a confirmation. + * 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. @@ -246,19 +280,155 @@ public class VoiceInteractor { } } + /** + * Select a single option from multiple potential options with the user via the trusted system + * VoiceInteractionService. Typically, the application would present this visually as + * a list view to allow selecting the option by touch. + * The result of the confirmation will be returned through an asynchronous call to + * either {@link #onPickOptionResult} or {@link #onCancel()}. + */ + public static class PickOptionRequest extends Request { + final CharSequence mPrompt; + final Option[] mOptions; + final Bundle mExtras; + + /** + * Represents a single option that the user may select using their voice. + */ + public static final class Option implements Parcelable { + final CharSequence mLabel; + ArrayList<CharSequence> mSynonyms; + Bundle mExtras; + + /** + * 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. + */ + public Option(CharSequence label) { + mLabel = label; + } + + /** + * 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. + */ + public Option addSynonym(CharSequence synonym) { + if (mSynonyms == null) { + mSynonyms = new ArrayList<>(); + } + mSynonyms.add(synonym); + return this; + } + + public CharSequence getLabel() { + return mLabel; + } + + public int countSynonyms() { + return mSynonyms != null ? mSynonyms.size() : 0; + } + + public CharSequence getSynonymAt(int index) { + return mSynonyms != null ? mSynonyms.get(index) : null; + } + + /** + * Set optional extra information associated with this option. Note that this + * method takes ownership of the supplied extras Bundle. + */ + public void setExtras(Bundle extras) { + mExtras = extras; + } + + /** + * Return any optional extras information associated with this option, or null + * if there is none. Note that this method returns a reference to the actual + * extras Bundle in the option, so modifications to it will directly modify the + * extras in the option. + */ + public Bundle getExtras() { + return mExtras; + } + + Option(Parcel in) { + mLabel = in.readCharSequence(); + mSynonyms = in.readCharSequenceList(); + mExtras = in.readBundle(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeCharSequence(mLabel); + dest.writeCharSequenceList(mSynonyms); + dest.writeBundle(mExtras); + } + + public static final Parcelable.Creator<Option> CREATOR + = new Parcelable.Creator<Option>() { + public Option createFromParcel(Parcel in) { + return new Option(in); + } + + public Option[] newArray(int size) { + return new Option[size]; + } + }; + }; + + /** + * Create a new pick option request. + * @param prompt Optional question to be spoken to the user via text to speech. + * @param options The set of {@link Option}s the user is selecting from. + * @param extras Additional optional information. + */ + public PickOptionRequest(CharSequence prompt, Option[] options, Bundle extras) { + mPrompt = prompt; + mOptions = options; + mExtras = extras; + } + + /** + * 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. + * @param selections Either a single {@link Option} or one of several {@link Option}s the + * user has narrowed the choices down to. + * @param result Additional optional information. + */ + public void onPickOptionResult(boolean finished, Option[] selections, Bundle result) { + } + + IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName, + IVoiceInteractorCallback callback) throws RemoteException { + return interactor.startPickOption(packageName, callback, mPrompt, mOptions, mExtras); + } + } + + /** + * Reports that the current interaction was successfully completed with voice, so the + * application can report the final status to the user. When the response comes back, the + * voice system has handled the request and is ready to switch; at that point the + * application can start a new non-voice activity or finish. Be sure when starting the new + * activity to use {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK + * Intent.FLAG_ACTIVITY_NEW_TASK} to keep the new activity out of the current voice + * interaction task. + */ public static class CompleteVoiceRequest extends Request { final CharSequence mMessage; final Bundle mExtras; /** - * Reports that the current interaction was successfully completed with voice, so the - * application can report the final status to the user. When the response comes back, the - * voice system has handled the request and is ready to switch; at that point the - * application can start a new non-voice activity or finish. Be sure when starting the new - * activity to use {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK - * Intent.FLAG_ACTIVITY_NEW_TASK} to keep the new activity out of the current voice - * interaction task. - * + * 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. */ @@ -276,21 +446,23 @@ public class VoiceInteractor { } } + /** + * Reports that the current interaction can not be complete with voice, so the + * application will need to switch to a traditional input UI. Applications should + * only use this when they need to completely bail out of the voice interaction + * and switch to a traditional UI. When the response comes back, the voice + * system has handled the request and is ready to switch; at that point the application + * can start a new non-voice activity. Be sure when starting the new activity + * to use {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK + * Intent.FLAG_ACTIVITY_NEW_TASK} to keep the new activity out of the current voice + * interaction task. + */ public static class AbortVoiceRequest extends Request { final CharSequence mMessage; final Bundle mExtras; /** - * Reports that the current interaction can not be complete with voice, so the - * application will need to switch to a traditional input UI. Applications should - * only use this when they need to completely bail out of the voice interaction - * and switch to a traditional UI. When the response comes back, the voice - * system has handled the request and is ready to switch; at that point the application - * can start a new non-voice activity. Be sure when starting the new activity - * to use {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK - * Intent.FLAG_ACTIVITY_NEW_TASK} to keep the new activity out of the current voice - * interaction task. - * + * 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. @@ -309,25 +481,27 @@ public class VoiceInteractor { } } + /** + * Execute an extended 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). + * The result of the confirmation will be returned through an asynchronous call to + * either {@link #onCommandResult(boolean, android.os.Bundle)} or + * {@link #onCancel()}. + * + * <p>The command is a string that describes the generic operation to be performed. + * The command will determine how the properties in extras are interpreted and the set of + * available commands is expected to grow over time. 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.) + */ public static class CommandRequest extends Request { final String mCommand; final Bundle mArgs; /** - * Execute a 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). - * The result of the confirmation will be returned through an asynchronous call to - * either {@link #onCommandResult(boolean, android.os.Bundle)} or - * {@link #onCancel()}. - * - * <p>The command is a string that describes the generic operation to be performed. - * The command will determine how the properties in extras are interpreted and the set of - * available commands is expected to grow over time. 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.) - * + * Create a new generic command request. * @param command The desired command to perform. * @param args Additional arguments to control execution of the command. */ diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 2ed8c44ddc2f..f68547599719 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2790,6 +2790,31 @@ public class Intent implements Parcelable, Cloneable { /** {@hide} */ public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR"; + /** + * Broadcast action: report that a settings element is being restored from backup. The intent + * contains three extras: EXTRA_SETTING_NAME is a string naming the restored setting, + * EXTRA_SETTING_NEW_VALUE is the value being restored, and EXTRA_SETTING_PREVIOUS_VALUE + * is the value of that settings entry prior to the restore operation. All of these values are + * represented as strings. + * + * <p>This broadcast is sent only for settings provider entries known to require special handling + * around restore time. These entries are found in the BROADCAST_ON_RESTORE table within + * the provider's backup agent implementation. + * + * @see #EXTRA_SETTING_NAME + * @see #EXTRA_SETTING_PREVIOUS_VALUE + * @see #EXTRA_SETTING_NEW_VALUE + * {@hide} + */ + public static final String ACTION_SETTING_RESTORED = "android.os.action.SETTING_RESTORED"; + + /** {@hide} */ + public static final String EXTRA_SETTING_NAME = "setting_name"; + /** {@hide} */ + public static final String EXTRA_SETTING_PREVIOUS_VALUE = "previous_value"; + /** {@hide} */ + public static final String EXTRA_SETTING_NEW_VALUE = "new_value"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent categories (see addCategory()). diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java index 33d539c25e73..f16d650c5e7e 100644 --- a/core/java/android/hardware/camera2/DngCreator.java +++ b/core/java/android/hardware/camera2/DngCreator.java @@ -453,7 +453,7 @@ public final class DngCreator implements AutoCloseable { height + ") passed to write"); } long capacity = pixels.capacity(); - long totalSize = rowStride * height + offset; + long totalSize = ((long) rowStride) * height + offset; if (capacity < totalSize) { throw new IllegalArgumentException("Image size " + capacity + " is too small (must be larger than " + totalSize + ")"); diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 3d5215b6f036..9d8a1bafb93e 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -1059,6 +1059,21 @@ public final class Parcel { } } + /** + * @hide + */ + public final void writeCharSequenceList(ArrayList<CharSequence> val) { + if (val != null) { + int N = val.size(); + writeInt(N); + for (int i=0; i<N; i++) { + writeCharSequence(val.get(i)); + } + } else { + writeInt(-1); + } + } + public final IBinder[] createBinderArray() { int N = readInt(); if (N >= 0) { @@ -1828,6 +1843,25 @@ public final class Parcel { } /** + * Read and return an ArrayList<CharSequence> object from the parcel. + * {@hide} + */ + public final ArrayList<CharSequence> readCharSequenceList() { + ArrayList<CharSequence> array = null; + + int length = readInt(); + if (length >= 0) { + array = new ArrayList<CharSequence>(length); + + for (int i = 0 ; i < length ; i++) { + array.add(readCharSequence()); + } + } + + return array; + } + + /** * Read and return a new ArrayList object from the parcel at the current * dataPosition(). Returns null if the previously written list object was * null. The given class loader will be used to load any enclosed diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java index 29f9ca13f61e..66642debc032 100644 --- a/core/java/android/preference/PreferenceFragment.java +++ b/core/java/android/preference/PreferenceFragment.java @@ -17,6 +17,7 @@ package android.preference; import android.annotation.Nullable; +import android.annotation.XmlRes; import android.app.Activity; import android.app.Fragment; import android.content.Intent; @@ -294,7 +295,7 @@ public abstract class PreferenceFragment extends Fragment implements * * @param preferencesResId The XML resource ID to inflate. */ - public void addPreferencesFromResource(int preferencesResId) { + public void addPreferencesFromResource(@XmlRes int preferencesResId) { requirePreferenceManager(); setPreferenceScreen(mPreferenceManager.inflateFromResource(getActivity(), diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 0cc3255a0ec3..381327751636 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5374,6 +5374,7 @@ public final class Settings { ACCESSIBILITY_SCRIPT_INJECTION, BACKUP_AUTO_RESTORE, ENABLED_ACCESSIBILITY_SERVICES, + ENABLED_NOTIFICATION_LISTENERS, TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, TOUCH_EXPLORATION_ENABLED, ACCESSIBILITY_ENABLED, diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 4cf0e4ca8765..11eaa0678870 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -18,6 +18,7 @@ package android.service.voice; import android.app.Dialog; import android.app.Instrumentation; +import android.app.VoiceInteractor; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; @@ -105,6 +106,17 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } @Override + 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)); + return request.mInterface; + } + + @Override public IVoiceInteractorRequest startCompleteVoice(String callingPackage, IVoiceInteractorCallback callback, CharSequence message, Bundle extras) { Request request = newRequest(callback); @@ -232,6 +244,20 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } } + public void sendPickOptionResult(boolean finished, + VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) { + try { + if (DEBUG) Log.d(TAG, "sendPickOptionResult: req=" + mInterface + + " finished=" + finished + " selections=" + selections + + " result=" + result); + if (finished) { + finishRequest(); + } + mCallback.deliverPickOptionResult(mInterface, finished, selections, result); + } catch (RemoteException e) { + } + } + public void sendCompleteVoiceResult(Bundle result) { try { if (DEBUG) Log.d(TAG, "sendCompleteVoiceResult: req=" + mInterface @@ -252,12 +278,14 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } } - public void sendCommandResult(boolean complete, Bundle result) { + public void sendCommandResult(boolean finished, Bundle result) { try { if (DEBUG) Log.d(TAG, "sendCommandResult: req=" + mInterface + " result=" + result); - finishRequest(); - mCallback.deliverCommandResult(mInterface, complete, result); + if (finished) { + finishRequest(); + } + mCallback.deliverCommandResult(mInterface, finished, result); } catch (RemoteException e) { } } @@ -283,11 +311,12 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } static final int MSG_START_CONFIRMATION = 1; - static final int MSG_START_COMPLETE_VOICE = 2; - static final int MSG_START_ABORT_VOICE = 3; - static final int MSG_START_COMMAND = 4; - static final int MSG_SUPPORTS_COMMANDS = 5; - static final int MSG_CANCEL = 6; + static final int MSG_START_PICK_OPTION = 2; + static final int MSG_START_COMPLETE_VOICE = 3; + static final int MSG_START_ABORT_VOICE = 4; + static final int MSG_START_COMMAND = 5; + static final int MSG_SUPPORTS_COMMANDS = 6; + static final int MSG_CANCEL = 7; static final int MSG_TASK_STARTED = 100; static final int MSG_TASK_FINISHED = 101; @@ -309,6 +338,15 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { onConfirm((Caller)args.arg1, (Request)args.arg2, (CharSequence)args.arg3, (Bundle)args.arg4); 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); + break; case MSG_START_COMPLETE_VOICE: args = (SomeArgs)msg.obj; if (DEBUG) Log.d(TAG, "onCompleteVoice: req=" + ((Request) args.arg2).mInterface @@ -614,6 +652,26 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } /** + * Set whether this session will keep the device awake while it is running a voice + * activity. By default, the system holds a wake lock for it while in this state, + * so that it can work even if the screen is off. Setting this to false removes that + * wake lock, allowing the CPU to go to sleep. This is typically used if the + * session decides it has been waiting too long for a response from the user and + * doesn't want to let this continue to drain the battery. + * + * <p>Passing false here will release the wake lock, and you can call later with + * true to re-acquire it. It will also be automatically re-acquired for you each + * time you start a new voice activity task -- that is when you call + * {@link #startVoiceActivity}.</p> + */ + public void setKeepAwake(boolean keepAwake) { + try { + mSystemService.setKeepAwake(mToken, keepAwake); + } catch (RemoteException e) { + } + } + + /** * Convenience for inflating views. */ public LayoutInflater getLayoutInflater() { @@ -814,6 +872,22 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { Bundle extras); /** + * 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); + + /** * Request to complete the voice interaction session because the voice activity successfully * completed its interaction using voice. Corresponds to * {@link android.app.VoiceInteractor.CompleteVoiceRequest diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index 668e028b7729..13fb657812c0 100644 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -918,7 +918,7 @@ public class TextToSpeech { * * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. */ - public int addSpeech(CharSequence text, String packagename, int resourceId) { + public int addSpeech(CharSequence text, String packagename, @RawRes int resourceId) { synchronized (mStartLock) { mUtterances.put(text, makeResourceUri(packagename, resourceId)); return SUCCESS; diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java index 9009d6ab08d5..a7d9503a7718 100644 --- a/core/java/android/transition/TransitionInflater.java +++ b/core/java/android/transition/TransitionInflater.java @@ -16,6 +16,7 @@ package android.transition; +import android.annotation.TransitionRes; import com.android.internal.R; import org.xmlpull.v1.XmlPullParser; @@ -71,7 +72,8 @@ public class TransitionInflater { * @throws android.content.res.Resources.NotFoundException when the * transition cannot be loaded */ - public Transition inflateTransition(int resource) { + public Transition inflateTransition(@TransitionRes int resource) { + //noinspection ResourceType XmlResourceParser parser = mContext.getResources().getXml(resource); try { return createTransitionFromXml(parser, Xml.asAttributeSet(parser), null); @@ -98,7 +100,9 @@ public class TransitionInflater { * @throws android.content.res.Resources.NotFoundException when the * transition manager cannot be loaded */ - public TransitionManager inflateTransitionManager(int resource, ViewGroup sceneRoot) { + public TransitionManager inflateTransitionManager(@TransitionRes int resource, + ViewGroup sceneRoot) { + //noinspection ResourceType XmlResourceParser parser = mContext.getResources().getXml(resource); try { return createTransitionManagerFromXml(parser, Xml.asAttributeSet(parser), sceneRoot); diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java index d9f60541f2d2..9047b1dd73a2 100644 --- a/core/java/android/view/ContextThemeWrapper.java +++ b/core/java/android/view/ContextThemeWrapper.java @@ -16,6 +16,7 @@ package android.view; +import android.annotation.StyleRes; import android.content.Context; import android.content.ContextWrapper; import android.content.res.Configuration; @@ -36,7 +37,7 @@ public class ContextThemeWrapper extends ContextWrapper { super(null); } - public ContextThemeWrapper(Context base, int themeResId) { + public ContextThemeWrapper(Context base, @StyleRes int themeResId) { super(base); mThemeResource = themeResId; } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 3927096a856b..d345bed0ec28 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -24,6 +24,7 @@ import android.annotation.DrawableRes; import android.annotation.FloatRange; import android.annotation.IdRes; import android.annotation.IntDef; +import android.annotation.LayoutRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; @@ -18646,7 +18647,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * layout_* parameters. * @see LayoutInflater */ - public static View inflate(Context context, int resource, ViewGroup root) { + public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { LayoutInflater factory = LayoutInflater.from(context); return factory.inflate(resource, root); } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index f36fd5affbb7..9a929323f864 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -22,6 +22,7 @@ import android.annotation.IdRes; import android.annotation.LayoutRes; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.StyleRes; import android.annotation.SystemApi; import android.content.Context; import android.content.res.Configuration; @@ -753,7 +754,7 @@ public abstract class Window { * 0 here will override the animations the window would * normally retrieve from its theme. */ - public void setWindowAnimations(int resId) { + public void setWindowAnimations(@StyleRes int resId) { final WindowManager.LayoutParams attrs = getAttributes(); attrs.windowAnimations = resId; dispatchWindowAttributesChanged(attrs); diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java index a5524d86b203..be439523b341 100644 --- a/core/java/android/view/animation/Animation.java +++ b/core/java/android/view/animation/Animation.java @@ -17,6 +17,7 @@ package android.view.animation; import android.annotation.ColorInt; +import android.annotation.InterpolatorRes; import android.content.Context; import android.content.res.TypedArray; import android.graphics.RectF; @@ -388,7 +389,7 @@ public abstract class Animation implements Cloneable { * @param resID The resource identifier of the interpolator to load * @attr ref android.R.styleable#Animation_interpolator */ - public void setInterpolator(Context context, int resID) { + public void setInterpolator(Context context, @InterpolatorRes int resID) { setInterpolator(AnimationUtils.loadInterpolator(context, resID)); } diff --git a/core/java/android/view/animation/LayoutAnimationController.java b/core/java/android/view/animation/LayoutAnimationController.java index 882e738eaa11..df2f18c21735 100644 --- a/core/java/android/view/animation/LayoutAnimationController.java +++ b/core/java/android/view/animation/LayoutAnimationController.java @@ -16,6 +16,8 @@ package android.view.animation; +import android.annotation.AnimRes; +import android.annotation.InterpolatorRes; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; @@ -180,7 +182,7 @@ public class LayoutAnimationController { * * @attr ref android.R.styleable#LayoutAnimation_animation */ - public void setAnimation(Context context, int resourceID) { + public void setAnimation(Context context, @AnimRes int resourceID) { setAnimation(AnimationUtils.loadAnimation(context, resourceID)); } @@ -225,7 +227,7 @@ public class LayoutAnimationController { * * @attr ref android.R.styleable#LayoutAnimation_interpolator */ - public void setInterpolator(Context context, int resourceID) { + public void setInterpolator(Context context, @InterpolatorRes int resourceID) { setInterpolator(AnimationUtils.loadInterpolator(context, resourceID)); } diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java index 9d3a5dc15756..d6f227615909 100644 --- a/core/java/android/widget/ActionMenuView.java +++ b/core/java/android/widget/ActionMenuView.java @@ -15,6 +15,7 @@ */ package android.widget; +import android.annotation.StyleRes; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Configuration; @@ -86,7 +87,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo * @param resId theme used to inflate popup menus * @see #getPopupTheme() */ - public void setPopupTheme(int resId) { + public void setPopupTheme(@StyleRes int resId) { if (mPopupTheme != resId) { mPopupTheme = resId; if (resId == 0) { diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java index 89e508fdb97b..ae94a10ff036 100644 --- a/core/java/android/widget/ArrayAdapter.java +++ b/core/java/android/widget/ArrayAdapter.java @@ -19,6 +19,7 @@ package android.widget; import android.annotation.ArrayRes; import android.annotation.IdRes; import android.annotation.LayoutRes; +import android.annotation.NonNull; import android.content.Context; import android.content.res.Resources; import android.util.Log; @@ -133,7 +134,7 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable, * instantiating views. * @param objects The objects to represent in the ListView. */ - public ArrayAdapter(Context context, @LayoutRes int resource, T[] objects) { + public ArrayAdapter(Context context, @LayoutRes int resource, @NonNull T[] objects) { this(context, resource, 0, Arrays.asList(objects)); } @@ -146,7 +147,8 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable, * @param textViewResourceId The id of the TextView within the layout resource to be populated * @param objects The objects to represent in the ListView. */ - public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId, T[] objects) { + public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId, + @NonNull T[] objects) { this(context, resource, textViewResourceId, Arrays.asList(objects)); } @@ -158,7 +160,7 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable, * instantiating views. * @param objects The objects to represent in the ListView. */ - public ArrayAdapter(Context context, @LayoutRes int resource, List<T> objects) { + public ArrayAdapter(Context context, @LayoutRes int resource, @NonNull List<T> objects) { this(context, resource, 0, objects); } @@ -171,7 +173,8 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable, * @param textViewResourceId The id of the TextView within the layout resource to be populated * @param objects The objects to represent in the ListView. */ - public ArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects) { + public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId, + @NonNull List<T> objects) { mContext = context; mInflater = LayoutInflater.from(context); mResource = mDropDownResource = resource; diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java index fe143dec8900..133e10250519 100644 --- a/core/java/android/widget/FastScroller.java +++ b/core/java/android/widget/FastScroller.java @@ -22,6 +22,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; +import android.annotation.StyleRes; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; @@ -326,7 +327,7 @@ class FastScroller { refreshDrawablePressedState(); } - public void setStyle(int resId) { + public void setStyle(@StyleRes int resId) { final Context context = mList.getContext(); final TypedArray ta = context.obtainStyledAttributes(null, com.android.internal.R.styleable.FastScroll, android.R.attr.fastScrollStyle, resId); diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java index a65671283816..2008ba8f0d88 100644 --- a/core/java/android/widget/SimpleAdapter.java +++ b/core/java/android/widget/SimpleAdapter.java @@ -16,6 +16,8 @@ package android.widget; +import android.annotation.IdRes; +import android.annotation.LayoutRes; import android.content.Context; import android.content.res.Resources; import android.view.ContextThemeWrapper; @@ -82,7 +84,7 @@ public class SimpleAdapter extends BaseAdapter implements Filterable, Spinner.Th * in the from parameter. */ public SimpleAdapter(Context context, List<? extends Map<String, ?>> data, - int resource, String[] from, int[] to) { + @LayoutRes int resource, String[] from, @IdRes int[] to) { mData = data; mResource = mDropDownResource = resource; mFrom = from; diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index d2430bc6b645..087406a35ca0 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -17,8 +17,12 @@ package android.widget; import android.annotation.ColorInt; +import android.annotation.DrawableRes; +import android.annotation.MenuRes; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.StringRes; +import android.annotation.StyleRes; import android.app.ActionBar; import android.content.Context; import android.content.res.ColorStateList; @@ -296,7 +300,7 @@ public class Toolbar extends ViewGroup { * @param resId theme used to inflate popup menus * @see #getPopupTheme() */ - public void setPopupTheme(int resId) { + public void setPopupTheme(@StyleRes int resId) { if (mPopupTheme != resId) { mPopupTheme = resId; if (resId == 0) { @@ -331,7 +335,7 @@ public class Toolbar extends ViewGroup { * * @param resId ID of a drawable resource */ - public void setLogo(int resId) { + public void setLogo(@DrawableRes int resId) { setLogo(getContext().getDrawable(resId)); } @@ -481,7 +485,7 @@ public class Toolbar extends ViewGroup { * * @param resId String resource id */ - public void setLogoDescription(int resId) { + public void setLogoDescription(@StringRes int resId) { setLogoDescription(getContext().getText(resId)); } @@ -566,7 +570,7 @@ public class Toolbar extends ViewGroup { * * @param resId Resource ID of a string to set as the title */ - public void setTitle(int resId) { + public void setTitle(@StringRes int resId) { setTitle(getContext().getText(resId)); } @@ -621,7 +625,7 @@ public class Toolbar extends ViewGroup { * * @param resId String resource ID */ - public void setSubtitle(int resId) { + public void setSubtitle(@StringRes int resId) { setSubtitle(getContext().getText(resId)); } @@ -663,7 +667,7 @@ public class Toolbar extends ViewGroup { * Sets the text color, size, style, hint color, and highlight color * from the specified TextAppearance resource. */ - public void setTitleTextAppearance(Context context, int resId) { + public void setTitleTextAppearance(Context context, @StyleRes int resId) { mTitleTextAppearance = resId; if (mTitleTextView != null) { mTitleTextView.setTextAppearance(context, resId); @@ -674,7 +678,7 @@ public class Toolbar extends ViewGroup { * Sets the text color, size, style, hint color, and highlight color * from the specified TextAppearance resource. */ - public void setSubtitleTextAppearance(Context context, int resId) { + public void setSubtitleTextAppearance(Context context, @StyleRes int resId) { mSubtitleTextAppearance = resId; if (mSubtitleTextView != null) { mSubtitleTextView.setTextAppearance(context, resId); @@ -729,7 +733,7 @@ public class Toolbar extends ViewGroup { * * @attr ref android.R.styleable#Toolbar_navigationContentDescription */ - public void setNavigationContentDescription(int resId) { + public void setNavigationContentDescription(@StringRes int resId) { setNavigationContentDescription(resId != 0 ? getContext().getText(resId) : null); } @@ -766,7 +770,7 @@ public class Toolbar extends ViewGroup { * * @attr ref android.R.styleable#Toolbar_navigationIcon */ - public void setNavigationIcon(int resId) { + public void setNavigationIcon(@DrawableRes int resId) { setNavigationIcon(getContext().getDrawable(resId)); } @@ -972,7 +976,7 @@ public class Toolbar extends ViewGroup { * * @param resId ID of a menu resource to inflate */ - public void inflateMenu(int resId) { + public void inflateMenu(@MenuRes int resId) { getMenuInflater().inflate(resId, getMenu()); } diff --git a/core/java/android/widget/ViewAnimator.java b/core/java/android/widget/ViewAnimator.java index f30fdd802b31..1580f515eee1 100644 --- a/core/java/android/widget/ViewAnimator.java +++ b/core/java/android/widget/ViewAnimator.java @@ -17,6 +17,7 @@ package android.widget; +import android.annotation.AnimRes; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; @@ -309,7 +310,7 @@ public class ViewAnimator extends FrameLayout { * @see #getInAnimation() * @see #setInAnimation(android.view.animation.Animation) */ - public void setInAnimation(Context context, int resourceID) { + public void setInAnimation(Context context, @AnimRes int resourceID) { setInAnimation(AnimationUtils.loadAnimation(context, resourceID)); } @@ -322,7 +323,7 @@ public class ViewAnimator extends FrameLayout { * @see #getOutAnimation() * @see #setOutAnimation(android.view.animation.Animation) */ - public void setOutAnimation(Context context, int resourceID) { + public void setOutAnimation(Context context, @AnimRes int resourceID) { setOutAnimation(AnimationUtils.loadAnimation(context, resourceID)); } diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index 8f549a6b5fc0..6450d5255b13 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -32,6 +32,7 @@ interface IVoiceInteractionManagerService { boolean showSessionFromSession(IBinder token, in Bundle sessionArgs, int flags); boolean hideSessionFromSession(IBinder token); int startVoiceActivity(IBinder token, in Intent intent, String resolvedType); + void setKeepAwake(IBinder token, boolean keepAwake); void finish(IBinder token); /** diff --git a/core/java/com/android/internal/app/IVoiceInteractor.aidl b/core/java/com/android/internal/app/IVoiceInteractor.aidl index 3e0b02167cca..84e9cf027096 100644 --- a/core/java/com/android/internal/app/IVoiceInteractor.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractor.aidl @@ -16,6 +16,7 @@ package com.android.internal.app; +import android.app.VoiceInteractor; import android.os.Bundle; import com.android.internal.app.IVoiceInteractorCallback; @@ -27,6 +28,9 @@ import com.android.internal.app.IVoiceInteractorRequest; interface IVoiceInteractor { IVoiceInteractorRequest startConfirmation(String callingPackage, IVoiceInteractorCallback callback, CharSequence prompt, in Bundle extras); + IVoiceInteractorRequest startPickOption(String callingPackage, + IVoiceInteractorCallback callback, CharSequence prompt, + in VoiceInteractor.PickOptionRequest.Option[] options, in Bundle extras); IVoiceInteractorRequest startCompleteVoice(String callingPackage, IVoiceInteractorCallback callback, CharSequence message, in Bundle extras); IVoiceInteractorRequest startAbortVoice(String callingPackage, diff --git a/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl b/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl index dcd57593c2ca..1331e744cdf0 100644 --- a/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl @@ -16,6 +16,7 @@ package com.android.internal.app; +import android.app.VoiceInteractor; import android.os.Bundle; import com.android.internal.app.IVoiceInteractorRequest; @@ -26,8 +27,10 @@ import com.android.internal.app.IVoiceInteractorRequest; oneway interface IVoiceInteractorCallback { void deliverConfirmationResult(IVoiceInteractorRequest request, boolean confirmed, in Bundle result); + void deliverPickOptionResult(IVoiceInteractorRequest request, boolean finished, + in VoiceInteractor.PickOptionRequest.Option[] selections, in Bundle result); void deliverCompleteVoiceResult(IVoiceInteractorRequest request, in Bundle result); void deliverAbortVoiceResult(IVoiceInteractorRequest request, in Bundle result); - void deliverCommandResult(IVoiceInteractorRequest request, boolean complete, in Bundle result); + void deliverCommandResult(IVoiceInteractorRequest request, boolean finished, in Bundle result); void deliverCancel(IVoiceInteractorRequest request); } diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java index 99286cba3d87..113768ecd4eb 100644 --- a/core/java/com/android/internal/os/HandlerCaller.java +++ b/core/java/com/android/internal/os/HandlerCaller.java @@ -164,6 +164,15 @@ public class HandlerCaller { return mH.obtainMessage(what, arg1, 0, args); } + public Message obtainMessageIIOOO(int what, int arg1, int arg2, Object arg3, Object arg4, + Object arg5) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = arg3; + args.arg2 = arg4; + args.arg3 = arg5; + return mH.obtainMessage(what, arg1, arg2, args); + } + public Message obtainMessageOO(int what, Object arg1, Object arg2) { SomeArgs args = SomeArgs.obtain(); args.arg1 = arg1; diff --git a/core/jni/android_database_SQLiteGlobal.cpp b/core/jni/android_database_SQLiteGlobal.cpp index d0c592e1461c..0a1c9f75edec 100644 --- a/core/jni/android_database_SQLiteGlobal.cpp +++ b/core/jni/android_database_SQLiteGlobal.cpp @@ -35,14 +35,18 @@ static const int SOFT_HEAP_LIMIT = 8 * 1024 * 1024; // Called each time a message is logged. -static void sqliteLogCallback(void* data, int iErrCode, const char* zMsg) { +static void sqliteLogCallback(void* data, int err, const char* msg) { bool verboseLog = !!data; - if (iErrCode == 0 || iErrCode == SQLITE_CONSTRAINT || iErrCode == SQLITE_SCHEMA) { + int errType = err & 255; + if (errType == 0 || errType == SQLITE_CONSTRAINT || errType == SQLITE_SCHEMA + || errType == SQLITE_NOTICE || err == SQLITE_WARNING_AUTOINDEX) { if (verboseLog) { - ALOG(LOG_VERBOSE, SQLITE_LOG_TAG, "(%d) %s\n", iErrCode, zMsg); + ALOG(LOG_VERBOSE, SQLITE_LOG_TAG, "(%d) %s\n", err, msg); } + } else if (errType == SQLITE_WARNING) { + ALOG(LOG_WARN, SQLITE_LOG_TAG, "(%d) %s\n", err, msg); } else { - ALOG(LOG_ERROR, SQLITE_LOG_TAG, "(%d) %s\n", iErrCode, zMsg); + ALOG(LOG_ERROR, SQLITE_LOG_TAG, "(%d) %s\n", err, msg); } } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index ed4776bab525..4d6b5f68aa77 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -90,6 +90,8 @@ <protected-broadcast android:name="android.appwidget.action.APPWIDGET_HOST_RESTORED" /> <protected-broadcast android:name="android.appwidget.action.APPWIDGET_RESTORED" /> + <protected-broadcast android:name="android.os.action.SETTING_RESTORED" /> + <protected-broadcast android:name="android.backup.intent.RUN" /> <protected-broadcast android:name="android.backup.intent.CLEAR" /> <protected-broadcast android:name="android.backup.intent.INIT" /> diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java index bddd224aba9a..69d68910c8b5 100644 --- a/graphics/java/android/graphics/PorterDuffColorFilter.java +++ b/graphics/java/android/graphics/PorterDuffColorFilter.java @@ -16,6 +16,7 @@ package android.graphics; +import android.annotation.ColorInt; import android.annotation.NonNull; /** @@ -36,7 +37,7 @@ public class PorterDuffColorFilter extends ColorFilter { * @see #setColor(int) * @see #setMode(android.graphics.PorterDuff.Mode) */ - public PorterDuffColorFilter(int color, @NonNull PorterDuff.Mode mode) { + public PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) { mColor = color; mMode = mode; update(); diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 16760c7e5769..56876e94af82 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -521,7 +521,7 @@ public abstract class Drawable { * {@link #setTintList(ColorStateList) tint}. * </p> */ - public void setColorFilter(int color, @NonNull PorterDuff.Mode mode) { + public void setColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) { setColorFilter(new PorterDuffColorFilter(color, mode)); } diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index 3c9ca4e78823..ebf73da0b82f 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -1972,7 +1972,7 @@ public final class MediaCodecInfo { (Integer)map.get(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL); if (complexity == null) { complexity = flacComplexity; - } else if (flacComplexity != null && complexity != flacComplexity) { + } else if (flacComplexity != null && !complexity.equals(flacComplexity)) { throw new IllegalArgumentException( "conflicting values for complexity and " + "flac-compression-level"); @@ -1985,7 +1985,7 @@ public final class MediaCodecInfo { Integer aacProfile = (Integer)map.get(MediaFormat.KEY_AAC_PROFILE); if (profile == null) { profile = aacProfile; - } else if (aacProfile != null && aacProfile != profile) { + } else if (aacProfile != null && !aacProfile.equals(profile)) { throw new IllegalArgumentException( "conflicting values for profile and aac-profile"); } diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index c44fbe6d6500..0c1c7e9b0c19 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -606,14 +606,14 @@ public final class MediaFormat { * Sets the value of an integer key. */ public final void setInteger(String name, int value) { - mMap.put(name, new Integer(value)); + mMap.put(name, Integer.valueOf(value)); } /** * Sets the value of a long key. */ public final void setLong(String name, long value) { - mMap.put(name, new Long(value)); + mMap.put(name, Long.valueOf(value)); } /** diff --git a/media/java/android/media/WebVttRenderer.java b/media/java/android/media/WebVttRenderer.java index 69e0ea639705..91c53fac1799 100644 --- a/media/java/android/media/WebVttRenderer.java +++ b/media/java/android/media/WebVttRenderer.java @@ -433,7 +433,9 @@ class TextTrackCue extends SubtitleTrack.Cue { mRegionId.equals(cue.mRegionId) && mSnapToLines == cue.mSnapToLines && mAutoLinePosition == cue.mAutoLinePosition && - (mAutoLinePosition || mLinePosition == cue.mLinePosition) && + (mAutoLinePosition || + ((mLinePosition != null && mLinePosition.equals(cue.mLinePosition)) || + (mLinePosition == null && cue.mLinePosition == null))) && mTextPosition == cue.mTextPosition && mSize == cue.mSize && mAlignment == cue.mAlignment && diff --git a/media/java/android/media/midi/MidiDeviceInfo.java b/media/java/android/media/midi/MidiDeviceInfo.java index f7fad3d2a85d..93e0939f0d84 100644 --- a/media/java/android/media/midi/MidiDeviceInfo.java +++ b/media/java/android/media/midi/MidiDeviceInfo.java @@ -173,8 +173,16 @@ public final class MidiDeviceInfo implements Parcelable { mId = id; mInputPortCount = numInputPorts; mOutputPortCount = numOutputPorts; - mInputPortNames = inputPortNames; - mOutputPortNames = outputPortNames; + if (inputPortNames == null) { + mInputPortNames = new String[numInputPorts]; + } else { + mInputPortNames = inputPortNames; + } + if (outputPortNames == null) { + mOutputPortNames = new String[numOutputPorts]; + } else { + mOutputPortNames = outputPortNames; + } mProperties = properties; mIsPrivate = isPrivate; } diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java index e0aacd65f01a..0284171d0501 100644 --- a/media/java/android/media/tv/TvTrackInfo.java +++ b/media/java/android/media/tv/TvTrackInfo.java @@ -42,6 +42,7 @@ public final class TvTrackInfo implements Parcelable { private final int mType; private final String mId; private final String mLanguage; + private final String mDescription; private final int mAudioChannelCount; private final int mAudioSampleRate; private final int mVideoWidth; @@ -49,12 +50,13 @@ public final class TvTrackInfo implements Parcelable { private final float mVideoFrameRate; private final Bundle mExtra; - private TvTrackInfo(int type, String id, String language, int audioChannelCount, - int audioSampleRate, int videoWidth, int videoHeight, float videoFrameRate, - Bundle extra) { + private TvTrackInfo(int type, String id, String language, String description, + int audioChannelCount, int audioSampleRate, int videoWidth, int videoHeight, + float videoFrameRate, Bundle extra) { mType = type; mId = id; mLanguage = language; + mDescription = description; mAudioChannelCount = audioChannelCount; mAudioSampleRate = audioSampleRate; mVideoWidth = videoWidth; @@ -67,6 +69,7 @@ public final class TvTrackInfo implements Parcelable { mType = in.readInt(); mId = in.readString(); mLanguage = in.readString(); + mDescription = in.readString(); mAudioChannelCount = in.readInt(); mAudioSampleRate = in.readInt(); mVideoWidth = in.readInt(); @@ -99,6 +102,13 @@ public final class TvTrackInfo implements Parcelable { } /** + * Returns a user readable description for the current track. + */ + public final String getDescription() { + return mDescription; + } + + /** * Returns the audio channel count. Valid only for {@link #TYPE_AUDIO} tracks. */ public final int getAudioChannelCount() { @@ -174,6 +184,7 @@ public final class TvTrackInfo implements Parcelable { dest.writeInt(mType); dest.writeString(mId); dest.writeString(mLanguage); + dest.writeString(mDescription); dest.writeInt(mAudioChannelCount); dest.writeInt(mAudioSampleRate); dest.writeInt(mVideoWidth); @@ -202,6 +213,7 @@ public final class TvTrackInfo implements Parcelable { private final String mId; private final int mType; private String mLanguage; + private String mDescription; private int mAudioChannelCount; private int mAudioSampleRate; private int mVideoWidth; @@ -241,6 +253,16 @@ public final class TvTrackInfo implements Parcelable { } /** + * Sets a user readable description for the current track. + * + * @param description The user readable description. + */ + public final Builder setDescription(String description) { + mDescription = description; + return this; + } + + /** * Sets the audio channel count. Valid only for {@link #TYPE_AUDIO} tracks. * * @param audioChannelCount The audio channel count. @@ -325,8 +347,8 @@ public final class TvTrackInfo implements Parcelable { * @return The new {@link TvTrackInfo} instance */ public TvTrackInfo build() { - return new TvTrackInfo(mType, mId, mLanguage, mAudioChannelCount, mAudioSampleRate, - mVideoWidth, mVideoHeight, mVideoFrameRate, mExtra); + return new TvTrackInfo(mType, mId, mLanguage, mDescription, mAudioChannelCount, + mAudioSampleRate, mVideoWidth, mVideoHeight, mVideoFrameRate, mExtra); } } -}
\ No newline at end of file +} diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index eac83d8e2563..7f826ef961db 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -793,7 +793,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { } // Figure out the white list and redirects to the global table. - String[] whitelist = null; + final String[] whitelist; if (contentUri.equals(Settings.Secure.CONTENT_URI)) { whitelist = Settings.Secure.SETTINGS_TO_BACKUP; } else if (contentUri.equals(Settings.System.CONTENT_URI)) { @@ -809,6 +809,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { Map<String, String> cachedEntries = new HashMap<String, String>(); ContentValues contentValues = new ContentValues(2); SettingsHelper settingsHelper = mSettingsHelper; + ContentResolver cr = getContentResolver(); final int whiteListSize = whitelist.length; for (int i = 0; i < whiteListSize; i++) { @@ -841,14 +842,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key)) ? Settings.Global.CONTENT_URI : contentUri; - - // The helper doesn't care what namespace the keys are in - if (settingsHelper.restoreValue(key, value)) { - contentValues.clear(); - contentValues.put(Settings.NameValueTable.NAME, key); - contentValues.put(Settings.NameValueTable.VALUE, value); - getContentResolver().insert(destination, contentValues); - } + settingsHelper.restoreValue(this, cr, contentValues, destination, key, value); if (DEBUG) { Log.d(TAG, "Restored setting: " + destination + " : "+ key + "=" + value); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java index 4144c803dbd3..30786f057fbf 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java @@ -19,7 +19,10 @@ package com.android.providers.settings; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.backup.IBackupManager; +import android.content.ContentResolver; +import android.content.ContentValues; import android.content.Context; +import android.content.Intent; import android.content.res.Configuration; import android.location.LocationManager; import android.media.AudioManager; @@ -28,10 +31,12 @@ import android.net.Uri; import android.os.IPowerManager; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.ArraySet; import java.util.Locale; @@ -41,6 +46,49 @@ public class SettingsHelper { private AudioManager mAudioManager; private TelephonyManager mTelephonyManager; + /** + * A few settings elements are special in that a restore of those values needs to + * be post-processed by relevant parts of the OS. A restore of any settings element + * mentioned in this table will therefore cause the system to send a broadcast with + * the {@link Intent#ACTION_SETTING_RESTORED} action, with extras naming the + * affected setting and supplying its pre-restore value for comparison. + * + * @see Intent#ACTION_SETTING_RESTORED + * @see System#SETTINGS_TO_BACKUP + * @see Secure#SETTINGS_TO_BACKUP + * @see Global#SETTINGS_TO_BACKUP + * + * {@hide} + */ + private static final ArraySet<String> sBroadcastOnRestore; + static { + sBroadcastOnRestore = new ArraySet<String>(2); + sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); + sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); + } + + private interface SettingsLookup { + public String lookup(ContentResolver resolver, String name, int userHandle); + } + + private static SettingsLookup sSystemLookup = new SettingsLookup() { + public String lookup(ContentResolver resolver, String name, int userHandle) { + return Settings.System.getStringForUser(resolver, name, userHandle); + } + }; + + private static SettingsLookup sSecureLookup = new SettingsLookup() { + public String lookup(ContentResolver resolver, String name, int userHandle) { + return Settings.Secure.getStringForUser(resolver, name, userHandle); + } + }; + + private static SettingsLookup sGlobalLookup = new SettingsLookup() { + public String lookup(ContentResolver resolver, String name, int userHandle) { + return Settings.Global.getStringForUser(resolver, name, userHandle); + } + }; + public SettingsHelper(Context context) { mContext = context; mAudioManager = (AudioManager) context @@ -58,24 +106,67 @@ public class SettingsHelper { * some cases the data will be written by the call to the appropriate API, * and in some cases the property value needs to be modified before setting. */ - public boolean restoreValue(String name, String value) { - if (Settings.System.SCREEN_BRIGHTNESS.equals(name)) { - setBrightness(Integer.parseInt(value)); - } else if (Settings.System.SOUND_EFFECTS_ENABLED.equals(name)) { - setSoundEffects(Integer.parseInt(value) == 1); - } else if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) { - setGpsLocation(value); - return false; - } else if (Settings.Secure.BACKUP_AUTO_RESTORE.equals(name)) { - setAutoRestore(Integer.parseInt(value) == 1); - } else if (isAlreadyConfiguredCriticalAccessibilitySetting(name)) { - return false; - } else if (Settings.System.RINGTONE.equals(name) - || Settings.System.NOTIFICATION_SOUND.equals(name)) { - setRingtone(name, value); - return false; + public void restoreValue(Context context, ContentResolver cr, ContentValues contentValues, + Uri destination, String name, String value) { + // Will we need a post-restore broadcast for this element? + String oldValue = null; + boolean sendBroadcast = false; + final SettingsLookup table; + + if (destination.equals(Settings.Secure.CONTENT_URI)) { + table = sSecureLookup; + } else if (destination.equals(Settings.System.CONTENT_URI)) { + table = sSystemLookup; + } else { /* must be GLOBAL; this was preflighted by the caller */ + table = sGlobalLookup; + } + + if (sBroadcastOnRestore.contains(name)) { + oldValue = table.lookup(cr, name, UserHandle.USER_OWNER); + sendBroadcast = true; + } + + try { + if (Settings.System.SCREEN_BRIGHTNESS.equals(name)) { + setBrightness(Integer.parseInt(value)); + // fall through to the ordinary write to settings + } else if (Settings.System.SOUND_EFFECTS_ENABLED.equals(name)) { + setSoundEffects(Integer.parseInt(value) == 1); + // fall through to the ordinary write to settings + } else if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) { + setGpsLocation(value); + return; + } else if (Settings.Secure.BACKUP_AUTO_RESTORE.equals(name)) { + setAutoRestore(Integer.parseInt(value) == 1); + } else if (isAlreadyConfiguredCriticalAccessibilitySetting(name)) { + return; + } else if (Settings.System.RINGTONE.equals(name) + || Settings.System.NOTIFICATION_SOUND.equals(name)) { + setRingtone(name, value); + return; + } + + // Default case: write the restored value to settings + contentValues.clear(); + contentValues.put(Settings.NameValueTable.NAME, name); + contentValues.put(Settings.NameValueTable.VALUE, value); + cr.insert(destination, contentValues); + } catch (Exception e) { + // If we fail to apply the setting, by definition nothing happened + sendBroadcast = false; + } finally { + // If this was an element of interest, send the "we just restored it" + // broadcast with the historical value now that the new value has + // been committed and observers kicked off. + if (sendBroadcast) { + Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED) + .setPackage("android").addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY) + .putExtra(Intent.EXTRA_SETTING_NAME, name) + .putExtra(Intent.EXTRA_SETTING_NEW_VALUE, value) + .putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, oldValue); + context.sendBroadcastAsUser(intent, UserHandle.OWNER, null); + } } - return true; } public String onBackupValue(String name, String value) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java index 6c1cdcd2e940..1e40babbda5d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java @@ -162,11 +162,6 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. public void updateNotification(NotificationData.Entry headsUp, boolean alert) { if (DEBUG) Log.v(TAG, "updateNotification"); - if (alert) { - mBar.scheduleHeadsUpDecay(mHeadsUpNotificationDecay); - } - invalidate(); - if (mHeadsUp == headsUp) { resetViewForHeadsup(); // This is an in-place update. Noting more to do. @@ -197,9 +192,11 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. } mHeadsUp.setInterruption(); - + } + if (alert) { // Make sure the heads up window is open. mBar.scheduleHeadsUpOpen(); + mBar.scheduleHeadsUpDecay(mHeadsUpNotificationDecay); } } diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java index d35213057eef..83aeedd9540e 100644 --- a/rs/java/android/renderscript/Script.java +++ b/rs/java/android/renderscript/Script.java @@ -239,8 +239,10 @@ public class Script extends BaseObj { FieldPacker v, LaunchOptions sc) { // TODO: Is this necessary if nScriptForEach calls validate as well? mRS.validate(); - for (Allocation ain : ains) { - mRS.validateObject(ain); + if (ains != null) { + for (Allocation ain : ains) { + mRS.validateObject(ain); + } } mRS.validateObject(aout); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index a712d789946c..bb5ff1b09bd7 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -352,6 +352,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { intentFilter.addAction(Intent.ACTION_USER_SWITCHED); intentFilter.addAction(Intent.ACTION_USER_REMOVED); intentFilter.addAction(Intent.ACTION_USER_PRESENT); + intentFilter.addAction(Intent.ACTION_SETTING_RESTORED); mContext.registerReceiverAsUser(new BroadcastReceiver() { @Override @@ -369,6 +370,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { onUserStateChangedLocked(userState); } } + } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) { + final String which = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); + if (Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES.equals(which)) { + synchronized (mLock) { + restoreEnabledAccessibilityServicesLocked( + intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE), + intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE)); + } + } } } }, UserHandle.ALL, intentFilter, null, null); @@ -857,6 +867,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } + // Called only during settings restore; currently supports only the owner user + void restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting) { + readComponentNamesFromStringLocked(oldSetting, mTempComponentNameSet, false); + readComponentNamesFromStringLocked(newSetting, mTempComponentNameSet, true); + + UserState userState = getUserStateLocked(UserHandle.USER_OWNER); + userState.mEnabledServices.clear(); + userState.mEnabledServices.addAll(mTempComponentNameSet); + persistComponentNamesToSettingLocked( + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + userState.mEnabledServices, + UserHandle.USER_OWNER); + onUserStateChangedLocked(userState); + } + private InteractionBridge getInteractionBridgeLocked() { if (mInteractionBridge == null) { mInteractionBridge = new InteractionBridge(); @@ -1129,10 +1154,27 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { Set<ComponentName> outComponentNames) { String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), settingName, userId); - outComponentNames.clear(); - if (settingValue != null) { + readComponentNamesFromStringLocked(settingValue, outComponentNames, false); + } + + /** + * Populates a set with the {@link ComponentName}s contained in a colon-delimited string. + * + * @param names The colon-delimited string to parse. + * @param outComponentNames The set of component names to be populated based on + * the contents of the <code>names</code> string. + * @param doMerge If true, the parsed component names will be merged into the output + * set, rather than replacing the set's existing contents entirely. + */ + private void readComponentNamesFromStringLocked(String names, + Set<ComponentName> outComponentNames, + boolean doMerge) { + if (!doMerge) { + outComponentNames.clear(); + } + if (names != null) { TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; - splitter.setString(settingValue); + splitter.setString(names); while (splitter.hasNext()) { String str = splitter.next(); if (str == null || str.length() <= 0) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e7952c1a9b60..a366c7bb9003 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -51,6 +51,8 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.BatteryStats; import android.os.PersistableBundle; +import android.os.PowerManager; +import android.os.WorkSource; import android.os.storage.IMountService; import android.os.storage.StorageManager; import android.service.voice.IVoiceInteractionSession; @@ -991,7 +993,14 @@ public final class ActivityManagerService extends ActivityManagerNative * Set while we are running a voice interaction. This overrides * sleeping while it is active. */ - private boolean mRunningVoice = false; + private IVoiceInteractionSession mRunningVoice; + + /** + * We want to hold a wake lock while running a voice interaction session, since + * this may happen with the screen off and we need to keep the CPU running to + * be able to continue to interact with the user. + */ + PowerManager.WakeLock mVoiceWakeLock; /** * State of external calls telling us if the device is awake or asleep. @@ -2269,6 +2278,9 @@ public final class ActivityManagerService extends ActivityManagerNative public void initPowerManagement() { mStackSupervisor.initPowerManagement(); mBatteryStatsService.initPowerManagement(); + PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); + mVoiceWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*voice*"); + mVoiceWakeLock.setReferenceCounted(false); } @Override @@ -2472,7 +2484,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedActivityLocked: r=" + r); mFocusedActivity = r; if (r.task != null && r.task.voiceInteractor != null) { - startRunningVoiceLocked(); + startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid); } else { finishRunningVoiceLocked(); } @@ -3628,6 +3640,19 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override + public void setVoiceKeepAwake(IVoiceInteractionSession session, boolean keepAwake) { + synchronized (this) { + if (mRunningVoice != null && mRunningVoice.asBinder() == session.asBinder()) { + if (keepAwake) { + mVoiceWakeLock.acquire(); + } else { + mVoiceWakeLock.release(); + } + } + } + } + + @Override public boolean startNextMatchingActivity(IBinder callingActivity, Intent intent, Bundle options) { // Refuse possible leaked file descriptors @@ -9685,8 +9710,8 @@ public final class ActivityManagerService extends ActivityManagerNative } void finishRunningVoiceLocked() { - if (mRunningVoice) { - mRunningVoice = false; + if (mRunningVoice != null) { + mRunningVoice = null; updateSleepIfNeededLocked(); } } @@ -9709,7 +9734,7 @@ public final class ActivityManagerService extends ActivityManagerNative private boolean shouldSleepLocked() { // Resume applications while running a voice interactor. - if (mRunningVoice) { + if (mRunningVoice != null) { return false; } @@ -9810,10 +9835,14 @@ public final class ActivityManagerService extends ActivityManagerNative + " mSleeping=" + mSleeping); } - void startRunningVoiceLocked() { - if (!mRunningVoice) { - mRunningVoice = true; - updateSleepIfNeededLocked(); + void startRunningVoiceLocked(IVoiceInteractionSession session, int targetUid) { + mVoiceWakeLock.setWorkSource(new WorkSource(targetUid)); + if (mRunningVoice == null || mRunningVoice.asBinder() != session.asBinder()) { + if (mRunningVoice == null) { + mVoiceWakeLock.acquire(); + updateSleepIfNeededLocked(); + } + mRunningVoice = session; } } @@ -12813,8 +12842,11 @@ public final class ActivityManagerService extends ActivityManagerNative + PowerManagerInternal.wakefulnessToString(mWakefulness)); pw.println(" mSleeping=" + mSleeping + " mLockScreenShown=" + lockScreenShownToString()); - pw.println(" mShuttingDown=" + mShuttingDown + " mRunningVoice=" + mRunningVoice - + " mTestPssMode=" + mTestPssMode); + pw.println(" mShuttingDown=" + mShuttingDown + " mTestPssMode=" + mTestPssMode); + if (mRunningVoice != null) { + pw.println(" mRunningVoice=" + mRunningVoice); + pw.println(" mVoiceWakeLock" + mVoiceWakeLock); + } } if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient || mOrigWaitForDebugger) { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index be9526868107..456ed3330eac 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -869,7 +869,7 @@ final class ActivityStack { // If we are not going to sleep, we want to ensure the device is // awake until the next activity is started. - if (!mService.isSleepingOrShuttingDown()) { + if (!uiSleeping && !mService.isSleepingOrShuttingDown()) { mStackSupervisor.acquireLaunchWakelock(); } @@ -1671,6 +1671,8 @@ final class ActivityStack { } } + mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid); + // We need to start pausing the current activity so the top one // can be resumed... boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0; diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index cbbb11a8dfb3..f56f65fa8ec9 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -84,6 +84,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; +import android.os.WorkSource; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.service.voice.IVoiceInteractionSession; @@ -316,8 +317,7 @@ public final class ActivityStackSupervisor implements DisplayListener { void initPowerManagement() { PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE); mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep"); - mLaunchingActivity = - pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch"); + mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*launch*"); mLaunchingActivity.setReferenceCounted(false); } @@ -2273,6 +2273,10 @@ public final class ActivityStackSupervisor implements DisplayListener { } } + void setLaunchSource(int uid) { + mLaunchingActivity.setWorkSource(new WorkSource(uid)); + } + void acquireLaunchWakelock() { if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) { throw new IllegalStateException("Calling must be system uid"); diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 0c7d71b1d0e7..9ccb2eaf1fb3 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -18,10 +18,12 @@ package com.android.server.notification; import android.app.ActivityManager; import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -51,6 +53,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.Set; /** @@ -74,6 +77,7 @@ abstract public class ManagedServices { private final UserProfiles mUserProfiles; private final SettingsObserver mSettingsObserver; private final Config mConfig; + private ArraySet<String> mRestored; // contains connections to all connected services, including app services // and system services @@ -91,6 +95,8 @@ abstract public class ManagedServices { // user change). private int[] mLastSeenProfileIds; + private final BroadcastReceiver mRestoreReceiver; + public ManagedServices(Context context, Handler handler, Object mutex, UserProfiles userProfiles) { mContext = context; @@ -98,6 +104,24 @@ abstract public class ManagedServices { mUserProfiles = userProfiles; mConfig = getConfig(); mSettingsObserver = new SettingsObserver(handler); + + mRestoreReceiver = new SettingRestoredReceiver(); + IntentFilter filter = new IntentFilter(Intent.ACTION_SETTING_RESTORED); + context.registerReceiver(mRestoreReceiver, filter); + } + + class SettingRestoredReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) { + String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); + if (Objects.equals(element, mConfig.secureSettingName)) { + String prevValue = intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE); + String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE); + settingRestored(element, prevValue, newValue, getSendingUserId()); + } + } + } } abstract protected Config getConfig(); @@ -140,6 +164,31 @@ abstract public class ManagedServices { } } + // By convention, restored settings are replicated to another settings + // entry, named similarly but with a disambiguation suffix. + public static final String restoredSettingName(Config config) { + return config.secureSettingName + ":restored"; + } + + // The OS has done a restore of this service's saved state. We clone it to the + // 'restored' reserve, and then once we return and the actual write to settings is + // performed, our observer will do the work of maintaining the restored vs live + // settings data. + public void settingRestored(String element, String oldValue, String newValue, int userid) { + if (DEBUG) Slog.d(TAG, "Restored managed service setting: " + element + + " ovalue=" + oldValue + " nvalue=" + newValue); + if (mConfig.secureSettingName.equals(element)) { + if (element != null) { + mRestored = null; + Settings.Secure.putStringForUser(mContext.getContentResolver(), + restoredSettingName(mConfig), + newValue, + userid); + disableNonexistentServices(userid); + } + } + } + public void onPackagesChanged(boolean queryReplace, String[] pkgList) { if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)) @@ -211,8 +260,23 @@ abstract public class ManagedServices { } private void disableNonexistentServices(int userId) { + final ContentResolver cr = mContext.getContentResolver(); + boolean restoredChanged = false; + if (mRestored == null) { + String restoredSetting = Settings.Secure.getStringForUser( + cr, + restoredSettingName(mConfig), + userId); + if (!TextUtils.isEmpty(restoredSetting)) { + if (DEBUG) Slog.d(TAG, "restored: " + restoredSetting); + String[] restored = restoredSetting.split(ENABLED_SERVICES_SEPARATOR); + mRestored = new ArraySet<String>(Arrays.asList(restored)); + } else { + mRestored = new ArraySet<String>(); + } + } String flatIn = Settings.Secure.getStringForUser( - mContext.getContentResolver(), + cr, mConfig.secureSettingName, userId); if (!TextUtils.isEmpty(flatIn)) { @@ -228,14 +292,16 @@ abstract public class ManagedServices { ResolveInfo resolveInfo = installedServices.get(i); ServiceInfo info = resolveInfo.serviceInfo; + ComponentName component = new ComponentName(info.packageName, info.name); if (!mConfig.bindPermission.equals(info.permission)) { Slog.w(TAG, "Skipping " + getCaption() + " service " + info.packageName + "/" + info.name + ": it does not require the permission " + mConfig.bindPermission); + restoredChanged |= mRestored.remove(component.flattenToString()); continue; } - installed.add(new ComponentName(info.packageName, info.name)); + installed.add(component); } String flatOut = ""; @@ -246,16 +312,27 @@ abstract public class ManagedServices { ComponentName enabledComponent = ComponentName.unflattenFromString(enabled[i]); if (installed.contains(enabledComponent)) { remaining.add(enabled[i]); + restoredChanged |= mRestored.remove(enabled[i]); } } + remaining.addAll(mRestored); flatOut = TextUtils.join(ENABLED_SERVICES_SEPARATOR, remaining); } if (DEBUG) Slog.v(TAG, "flat after: " + flatOut); if (!flatIn.equals(flatOut)) { - Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.putStringForUser(cr, mConfig.secureSettingName, flatOut, userId); } + if (restoredChanged) { + if (DEBUG) Slog.d(TAG, "restored changed; rewriting"); + final String flatRestored = TextUtils.join(ENABLED_SERVICES_SEPARATOR, + mRestored.toArray()); + Settings.Secure.putStringForUser(cr, + restoredSettingName(mConfig), + flatRestored, + userId); + } } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 6b8c49cc82fc..f032ccfba9c3 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -479,6 +479,24 @@ public class VoiceInteractionManagerService extends SystemService { } @Override + public void setKeepAwake(IBinder token, boolean keepAwake) { + synchronized (this) { + if (mImpl == null) { + Slog.w(TAG, "setKeepAwake without running voice interaction service"); + return; + } + final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); + final long caller = Binder.clearCallingIdentity(); + try { + mImpl.setKeepAwakeLocked(callingPid, callingUid, token, keepAwake); + } finally { + Binder.restoreCallingIdentity(caller); + } + } + } + + @Override public void finish(IBinder token) { synchronized (this) { if (mImpl == null) { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 9e92867349ce..5a91b88f147b 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -174,6 +174,18 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } + public void setKeepAwakeLocked(int callingPid, int callingUid, IBinder token, + boolean keepAwake) { + try { + if (mActiveSession == null || token != mActiveSession.mToken) { + Slog.w(TAG, "setKeepAwake does not match active session"); + return; + } + mAm.setVoiceKeepAwake(mActiveSession.mSession, keepAwake); + } catch (RemoteException e) { + throw new IllegalStateException("Unexpected remote error", e); + } + } public void finishLocked(int callingPid, int callingUid, IBinder token) { if (mActiveSession == null || token != mActiveSession.mToken) { diff --git a/tests/VoiceInteraction/res/layout/test_interaction.xml b/tests/VoiceInteraction/res/layout/test_interaction.xml index f4648b57dfab..8c8151d59ca0 100644 --- a/tests/VoiceInteraction/res/layout/test_interaction.xml +++ b/tests/VoiceInteraction/res/layout/test_interaction.xml @@ -41,6 +41,13 @@ android:text="@string/completeVoice" /> + <Button android:id="@+id/pick" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:text="@string/pickVoice" + /> + <Button android:id="@+id/abort" android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/tests/VoiceInteraction/res/values/strings.xml b/tests/VoiceInteraction/res/values/strings.xml index 9f99c97bbb69..5331457e22b1 100644 --- a/tests/VoiceInteraction/res/values/strings.xml +++ b/tests/VoiceInteraction/res/values/strings.xml @@ -22,7 +22,7 @@ <string name="complete">Complete</string> <string name="abortVoice">Abort Voice</string> <string name="completeVoice">Complete Voice</string> + <string name="pickVoice">Pick Voice</string> <string name="cancelVoice">Cancel</string> </resources> - diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java index bcfc6f436bfa..ad339befdd00 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java @@ -18,6 +18,7 @@ package com.android.test.voiceinteraction; import android.app.AssistContent; import android.app.AssistStructure; +import android.app.VoiceInteractor; import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -47,12 +48,15 @@ public class MainInteractionSession extends VoiceInteractionSession static final int STATE_IDLE = 0; static final int STATE_LAUNCHING = 1; static final int STATE_CONFIRM = 2; - static final int STATE_COMMAND = 3; - static final int STATE_ABORT_VOICE = 4; - static final int STATE_COMPLETE_VOICE = 5; - static final int STATE_DONE=6; + static final int STATE_PICK_OPTION = 3; + static final int STATE_COMMAND = 4; + static final int STATE_ABORT_VOICE = 5; + static final int STATE_COMPLETE_VOICE = 6; + static final int STATE_DONE=7; int mState = STATE_IDLE; + VoiceInteractor.PickOptionRequest.Option[] mPendingOptions; + CharSequence mPendingPrompt; Request mPendingRequest; MainInteractionSession(Context context) { @@ -154,7 +158,8 @@ public class MainInteractionSession extends VoiceInteractionSession mAssistVisualizer.setVisibility(View.GONE); } mStartButton.setEnabled(mState == STATE_IDLE); - mConfirmButton.setEnabled(mState == STATE_CONFIRM || mState == STATE_COMMAND); + mConfirmButton.setEnabled(mState == STATE_CONFIRM || mState == STATE_PICK_OPTION + || mState == STATE_COMMAND); mAbortButton.setEnabled(mState == STATE_ABORT_VOICE); mCompleteButton.setEnabled(mState == STATE_COMPLETE_VOICE); } @@ -167,10 +172,32 @@ public class MainInteractionSession extends VoiceInteractionSession } else if (v == mConfirmButton) { if (mState == STATE_CONFIRM) { mPendingRequest.sendConfirmResult(true, null); - } else { + mPendingRequest = null; + mState = STATE_LAUNCHING; + } else if (mState == STATE_PICK_OPTION) { + int numReturn = mPendingOptions.length/2; + if (numReturn <= 0) { + numReturn = 1; + } + VoiceInteractor.PickOptionRequest.Option[] picked + = new VoiceInteractor.PickOptionRequest.Option[numReturn]; + for (int i=0; i<picked.length; i++) { + picked[i] = mPendingOptions[i*2]; + } + mPendingOptions = picked; + if (picked.length <= 1) { + mPendingRequest.sendPickOptionResult(true, picked, null); + mPendingRequest = null; + mState = STATE_LAUNCHING; + } else { + mPendingRequest.sendPickOptionResult(false, picked, null); + updatePickText(); + } + } else if (mPendingRequest != null) { mPendingRequest.sendCommandResult(true, null); + mPendingRequest = null; + mState = STATE_LAUNCHING; } - mPendingRequest = null; } else if (v == mAbortButton) { mPendingRequest.sendAbortVoiceResult(null); mPendingRequest = null; @@ -178,6 +205,7 @@ public class MainInteractionSession extends VoiceInteractionSession mPendingRequest.sendCompleteVoiceResult(null); mPendingRequest = null; } + updateState(); } @Override @@ -198,13 +226,40 @@ public class MainInteractionSession extends VoiceInteractionSession public void onConfirm(Caller caller, Request request, CharSequence prompt, Bundle extras) { Log.i(TAG, "onConfirm: prompt=" + prompt + " extras=" + extras); mText.setText(prompt); - mStartButton.setText("Confirm"); + mConfirmButton.setText("Confirm"); mPendingRequest = request; + mPendingPrompt = prompt; mState = STATE_CONFIRM; updateState(); } @Override + public void onPickOption(Caller caller, Request request, CharSequence prompt, + VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) { + Log.i(TAG, "onPickOption: prompt=" + prompt + " options=" + options + " extras=" + extras); + mConfirmButton.setText("Pick Option"); + mPendingRequest = request; + mPendingPrompt = prompt; + mPendingOptions = options; + mState = STATE_PICK_OPTION; + updatePickText(); + updateState(); + } + + void updatePickText() { + StringBuilder sb = new StringBuilder(); + sb.append(mPendingPrompt); + sb.append(": "); + for (int i=0; i<mPendingOptions.length; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(mPendingOptions[i].getLabel()); + } + mText.setText(sb.toString()); + } + + @Override public void onCompleteVoice(Caller caller, Request request, CharSequence message, Bundle extras) { Log.i(TAG, "onCompleteVoice: message=" + message + " extras=" + extras); mText.setText(message); @@ -226,7 +281,7 @@ public class MainInteractionSession extends VoiceInteractionSession public void onCommand(Caller caller, Request request, String command, Bundle extras) { Log.i(TAG, "onCommand: command=" + command + " extras=" + extras); mText.setText("Command: " + command); - mStartButton.setText("Finish Command"); + mConfirmButton.setText("Finish Command"); mPendingRequest = request; mState = STATE_COMMAND; updateState(); diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java index 023e0ec79315..e195c30c1f7b 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java @@ -26,14 +26,17 @@ import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import android.widget.TextView; public class TestInteractionActivity extends Activity implements View.OnClickListener { static final String TAG = "TestInteractionActivity"; VoiceInteractor mInteractor; VoiceInteractor.Request mCurrentRequest = null; + TextView mLog; Button mAbortButton; Button mCompleteButton; + Button mPickButton; Button mCancelButton; @Override @@ -54,10 +57,13 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis } setContentView(R.layout.test_interaction); + mLog = (TextView)findViewById(R.id.log); mAbortButton = (Button)findViewById(R.id.abort); mAbortButton.setOnClickListener(this); mCompleteButton = (Button)findViewById(R.id.complete); mCompleteButton.setOnClickListener(this); + mPickButton = (Button)findViewById(R.id.pick); + mPickButton.setOnClickListener(this); mCancelButton = (Button)findViewById(R.id.cancel); mCancelButton.setOnClickListener(this); @@ -92,11 +98,13 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis @Override public void onCancel() { Log.i(TAG, "Canceled!"); + mLog.append("Canceled abort\n"); } @Override public void onAbortResult(Bundle result) { Log.i(TAG, "Abort result: result=" + result); + mLog.append("Abort: result=" + result + "\n"); getActivity().finish(); } }; @@ -107,15 +115,56 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis @Override public void onCancel() { Log.i(TAG, "Canceled!"); + mLog.append("Canceled complete\n"); } @Override public void onCompleteResult(Bundle result) { Log.i(TAG, "Complete result: result=" + result); + mLog.append("Complete: result=" + result + "\n"); getActivity().finish(); } }; mInteractor.submitRequest(req); + } else if (v == mPickButton) { + VoiceInteractor.PickOptionRequest.Option[] options = + new VoiceInteractor.PickOptionRequest.Option[5]; + options[0] = new VoiceInteractor.PickOptionRequest.Option("One"); + options[1] = new VoiceInteractor.PickOptionRequest.Option("Two"); + options[2] = new VoiceInteractor.PickOptionRequest.Option("Three"); + options[3] = new VoiceInteractor.PickOptionRequest.Option("Four"); + options[4] = new VoiceInteractor.PickOptionRequest.Option("Five"); + VoiceInteractor.PickOptionRequest req = new VoiceInteractor.PickOptionRequest( + "Need to pick something", options, null) { + @Override + public void onCancel() { + Log.i(TAG, "Canceled!"); + mLog.append("Canceled pick\n"); + } + + @Override + public void onPickOptionResult(boolean finished, Option[] selections, Bundle result) { + Log.i(TAG, "Pick result: finished=" + finished + " selections=" + selections + + " result=" + result); + StringBuilder sb = new StringBuilder(); + if (finished) { + sb.append("Pick final result: "); + } else { + sb.append("Pick intermediate result: "); + } + for (int i=0; i<selections.length; i++) { + if (i >= 1) { + sb.append(", "); + } + sb.append(selections[i].getLabel()); + } + mLog.append(sb.toString()); + if (finished) { + getActivity().finish(); + } + } + }; + mInteractor.submitRequest(req); } else if (v == mCancelButton && mCurrentRequest != null) { Log.i(TAG, "Cancel request"); mCurrentRequest.cancel(); diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp index b38b2eda4f73..d2cd2d64246c 100644 --- a/tools/aapt/XMLNode.cpp +++ b/tools/aapt/XMLNode.cpp @@ -466,7 +466,7 @@ void printXMLBlock(ResXMLTree* block) block->restart(); Vector<namespace_entry> namespaces; - + ResXMLTree::event_code_t code; int depth = 0; while ((code=block->next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { @@ -520,7 +520,12 @@ void printXMLBlock(ResXMLTree* block) printf("\n"); } } else if (code == ResXMLTree::END_TAG) { - depth--; + // Invalid tag nesting can be misused to break the parsing + // code below. Break if detected. + if (--depth < 0) { + printf("***BAD DEPTH in XMLBlock: %d\n", depth); + break; + } } else if (code == ResXMLTree::START_NAMESPACE) { namespace_entry ns; size_t len; @@ -536,7 +541,10 @@ void printXMLBlock(ResXMLTree* block) ns.uri.string()); depth++; } else if (code == ResXMLTree::END_NAMESPACE) { - depth--; + if (--depth < 0) { + printf("***BAD DEPTH in XMLBlock: %d\n", depth); + break; + } const namespace_entry& ns = namespaces.top(); size_t len; const char16_t* prefix16 = block->getNamespacePrefix(&len); @@ -714,7 +722,7 @@ const String8& XMLNode::getFilename() const { return mFilename; } - + const Vector<XMLNode::attribute_entry>& XMLNode::getAttributes() const { @@ -730,7 +738,7 @@ const XMLNode::attribute_entry* XMLNode::getAttribute(const String16& ns, return &ae; } } - + return NULL; } @@ -774,14 +782,14 @@ sp<XMLNode> XMLNode::searchElement(const String16& tagNamespace, const String16& && mElementName == tagName) { return this; } - + for (size_t i=0; i<mChildren.size(); i++) { sp<XMLNode> found = mChildren.itemAt(i)->searchElement(tagNamespace, tagName); if (found != NULL) { return found; } } - + return NULL; } @@ -795,7 +803,7 @@ sp<XMLNode> XMLNode::getChildElement(const String16& tagNamespace, const String1 return child; } } - + return NULL; } @@ -977,7 +985,7 @@ status_t XMLNode::parseValues(const sp<AaptAssets>& assets, ResourceTable* table) { bool hasErrors = false; - + if (getType() == TYPE_ELEMENT) { const size_t N = mAttributes.size(); String16 defPackage(assets->getPackage()); @@ -1013,7 +1021,7 @@ status_t XMLNode::assignResourceIds(const sp<AaptAssets>& assets, const ResourceTable* table) { bool hasErrors = false; - + if (getType() == TYPE_ELEMENT) { String16 attr("attr"); const char* errorMsg; @@ -1093,7 +1101,7 @@ status_t XMLNode::flatten(const sp<AaptFile>& dest, { StringPool strings(mUTF8); Vector<uint32_t> resids; - + // First collect just the strings for attribute names that have a // resource ID assigned to them. This ensures that the resource ID // array is compact, and makes it easier to deal with attribute names @@ -1141,7 +1149,7 @@ status_t XMLNode::flatten(const sp<AaptFile>& dest, dest->getSize(), (stringPool->getSize()*100)/dest->getSize(), dest->getPath().string()); } - + return NO_ERROR; } @@ -1217,7 +1225,7 @@ XMLNode::startNamespace(void *userData, const char *prefix, const char *uri) printf("Start Namespace: %s %s\n", prefix, uri); } ParseState* st = (ParseState*)userData; - sp<XMLNode> node = XMLNode::newNamespace(st->filename, + sp<XMLNode> node = XMLNode::newNamespace(st->filename, String16(prefix != NULL ? prefix : ""), String16(uri)); node->setStartLineNumber(XML_GetCurrentLineNumber(st->parser)); if (st->stack.size() > 0) { @@ -1338,7 +1346,7 @@ status_t XMLNode::collect_strings(StringPool* dest, Vector<uint32_t>* outResIds, bool stripComments, bool stripRawValues) const { collect_attr_strings(dest, outResIds, true); - + int i; if (RESOURCES_TOOLS_NAMESPACE != mNamespaceUri) { if (mNamespacePrefix.size() > 0) { |