diff options
34 files changed, 516 insertions, 157 deletions
diff --git a/api/current.txt b/api/current.txt index d1b6ba0..4ade5ed 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3937,6 +3937,7 @@ package android.app { public final class AssistData implements android.os.Parcelable { method public int describeContents(); + method public android.content.ComponentName getActivityComponent(); method public static android.app.AssistData getAssistData(android.os.Bundle); method public void getWindowAt(int, android.app.AssistData.ViewNode); method public int getWindowCount(); @@ -27644,9 +27645,10 @@ package android.service.voice { method public android.os.IBinder onBind(android.content.Intent); method public void onReady(); method public void onShutdown(); - method public void startSession(android.os.Bundle); + method public void startSession(android.os.Bundle, int); field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService"; field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction"; + field public static final int START_WITH_ASSIST = 1; // 0x1 } public abstract class VoiceInteractionSession implements android.view.KeyEvent.Callback { @@ -27664,10 +27666,11 @@ package android.service.voice { method public void onCompleteVoice(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle); method public void onComputeInsets(android.service.voice.VoiceInteractionSession.Insets); method public abstract void onConfirm(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle); - method public void onCreate(android.os.Bundle); + method public void onCreate(android.os.Bundle, int); method public android.view.View onCreateContentView(); method public void onDestroy(); method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]); + method public void onHandleAssist(android.os.Bundle); method public boolean onKeyDown(int, android.view.KeyEvent); method public boolean onKeyLongPress(int, android.view.KeyEvent); method public boolean onKeyMultiple(int, int, android.view.KeyEvent); diff --git a/api/system-current.txt b/api/system-current.txt index fd6e2c8..8a51d7c 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4027,6 +4027,7 @@ package android.app { public final class AssistData implements android.os.Parcelable { method public int describeContents(); + method public android.content.ComponentName getActivityComponent(); method public static android.app.AssistData getAssistData(android.os.Bundle); method public void getWindowAt(int, android.app.AssistData.ViewNode); method public int getWindowCount(); @@ -29331,9 +29332,10 @@ package android.service.voice { method public android.os.IBinder onBind(android.content.Intent); method public void onReady(); method public void onShutdown(); - method public void startSession(android.os.Bundle); + method public void startSession(android.os.Bundle, int); field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService"; field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction"; + field public static final int START_WITH_ASSIST = 1; // 0x1 } public abstract class VoiceInteractionSession implements android.view.KeyEvent.Callback { @@ -29351,10 +29353,11 @@ package android.service.voice { method public void onCompleteVoice(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle); method public void onComputeInsets(android.service.voice.VoiceInteractionSession.Insets); method public abstract void onConfirm(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle); - method public void onCreate(android.os.Bundle); + method public void onCreate(android.os.Bundle, int); method public android.view.View onCreateContentView(); method public void onDestroy(); method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]); + method public void onHandleAssist(android.os.Bundle); method public boolean onKeyDown(int, android.view.KeyEvent); method public boolean onKeyLongPress(int, android.view.KeyEvent); method public boolean onKeyMultiple(int, int, android.view.KeyEvent); diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 47f57ea..fa10893 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -51,6 +51,7 @@ import android.text.TextUtils; import android.util.Log; import android.util.Singleton; import com.android.internal.app.IVoiceInteractor; +import com.android.internal.os.IResultReceiver; import java.util.ArrayList; import java.util.List; @@ -2114,6 +2115,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + int requestType = data.readInt(); + IResultReceiver receiver = IResultReceiver.Stub.asInterface(data.readStrongBinder()); + requestAssistContextExtras(requestType, receiver); + reply.writeNoException(); + return true; + } + case REPORT_ASSIST_CONTEXT_EXTRAS_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder token = data.readStrongBinder(); @@ -5146,6 +5156,19 @@ class ActivityManagerProxy implements IActivityManager return res; } + public void requestAssistContextExtras(int requestType, IResultReceiver receiver) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeInt(requestType); + data.writeStrongBinder(receiver.asBinder()); + mRemote.transact(REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + public void reportAssistContextExtras(IBinder token, Bundle extras) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/app/AssistData.java b/core/java/android/app/AssistData.java index 8d3d348..7b5eb6d 100644 --- a/core/java/android/app/AssistData.java +++ b/core/java/android/app/AssistData.java @@ -16,6 +16,7 @@ package android.app; +import android.content.ComponentName; import android.graphics.Rect; import android.os.Bundle; import android.os.Parcel; @@ -44,6 +45,8 @@ final public class AssistData implements Parcelable { */ public static final String ASSIST_KEY = "android:assist"; + final ComponentName mActivityComponent; + final ArrayList<ViewNodeImpl> mRootViews = new ArrayList<>(); ViewAssistDataImpl mTmpViewAssistDataImpl = new ViewAssistDataImpl(); @@ -400,6 +403,7 @@ final public class AssistData implements Parcelable { } AssistData(Activity activity) { + mActivityComponent = activity.getComponentName(); ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews( activity.getActivityToken()); for (int i=0; i<views.size(); i++) { @@ -414,6 +418,7 @@ final public class AssistData implements Parcelable { } AssistData(Parcel in) { + mActivityComponent = ComponentName.readFromParcel(in); final int N = in.readInt(); for (int i=0; i<N; i++) { mRootViews.add(new ViewNodeImpl(in)); @@ -421,7 +426,9 @@ final public class AssistData implements Parcelable { //dump(); } - void dump() { + /** @hide */ + public void dump() { + Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString()); ViewNode node = new ViewNode(); final int N = getWindowCount(); for (int i=0; i<N; i++) { @@ -445,7 +452,7 @@ final public class AssistData implements Parcelable { } String text = node.getText(); if (text != null) { - Log.i(TAG, prefix + " Text (sel " + node.getTextSelectionStart() + "-" + Log.i(TAG, prefix + " Text (sel " + node.getTextSelectionStart() + "-" + node.getTextSelectionEnd() + "): " + text); } String hint = node.getHint(); @@ -476,6 +483,10 @@ final public class AssistData implements Parcelable { return assistBundle.getParcelable(ASSIST_KEY); } + public ComponentName getActivityComponent() { + return mActivityComponent; + } + /** * Return the number of window contents that have been collected in this assist data. */ @@ -498,6 +509,7 @@ final public class AssistData implements Parcelable { public void writeToParcel(Parcel out, int flags) { int start = out.dataPosition(); + ComponentName.writeToParcel(mActivityComponent, out); final int N = mRootViews.size(); out.writeInt(N); for (int i=0; i<N; i++) { diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 467c99a..341a2d7 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -51,6 +51,7 @@ import android.os.RemoteException; import android.os.StrictMode; import android.service.voice.IVoiceInteractionSession; import com.android.internal.app.IVoiceInteractor; +import com.android.internal.os.IResultReceiver; import java.util.List; @@ -419,6 +420,9 @@ public interface IActivityManager extends IInterface { public Bundle getAssistContextExtras(int requestType) throws RemoteException; + public void requestAssistContextExtras(int requestType, IResultReceiver receiver) + throws RemoteException; + public void reportAssistContextExtras(IBinder token, Bundle extras) throws RemoteException; public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle) @@ -804,4 +808,5 @@ public interface IActivityManager extends IInterface { int CREATE_STACK_ON_DISPLAY = IBinder.FIRST_CALL_TRANSACTION+281; int GET_FOCUSED_STACK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+282; int SET_TASK_RESIZEABLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+283; + int REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+284; } diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index fa5ac42..d410622 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -1039,10 +1039,10 @@ public class DreamService extends Service implements Window.Callback { protected void dump(final FileDescriptor fd, PrintWriter pw, final String[] args) { DumpUtils.dumpAsync(mHandler, new Dump() { @Override - public void dump(PrintWriter pw) { + public void dump(PrintWriter pw, String prefix) { dumpOnHandler(fd, pw, args); } - }, pw, 1000); + }, pw, "", 1000); } /** @hide */ diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl index 9f9c312..a8c0c4c 100644 --- a/core/java/android/service/voice/IVoiceInteractionSession.aidl +++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl @@ -17,11 +17,13 @@ package android.service.voice; import android.content.Intent; +import android.os.Bundle; /** * @hide */ oneway interface IVoiceInteractionSession { + void handleAssist(in Bundle assistData); void taskStarted(in Intent intent, int taskId); void taskFinished(in Intent intent, int taskId); void closeSystemDialogs(); diff --git a/core/java/android/service/voice/IVoiceInteractionSessionService.aidl b/core/java/android/service/voice/IVoiceInteractionSessionService.aidl index 2519442..7f8158f 100644 --- a/core/java/android/service/voice/IVoiceInteractionSessionService.aidl +++ b/core/java/android/service/voice/IVoiceInteractionSessionService.aidl @@ -24,5 +24,5 @@ import android.service.voice.IVoiceInteractionSession; * @hide */ oneway interface IVoiceInteractionSessionService { - void newSession(IBinder token, in Bundle args); + void newSession(IBinder token, in Bundle args, int startFlags); } diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index 65e6988..54a3a0a 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -70,6 +70,12 @@ public class VoiceInteractionService extends Service { */ public static final String SERVICE_META_DATA = "android.voice_interaction"; + /** + * Flag for use with {@link #startSession}: request that the session be started with + * assist data from the currently focused activity. + */ + public static final int START_WITH_ASSIST = 1<<0; + IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() { @Override public void ready() { mHandler.sendEmptyMessage(MSG_READY); @@ -136,16 +142,21 @@ public class VoiceInteractionService extends Service { * Initiate the execution of a new {@link android.service.voice.VoiceInteractionSession}. * @param args Arbitrary arguments that will be propagated to the session. */ - public void startSession(Bundle args) { + public void startSession(Bundle args, int flags) { if (mSystemService == null) { throw new IllegalStateException("Not available until onReady() is called"); } try { - mSystemService.startSession(mInterface, args); + mSystemService.startSession(mInterface, args, flags); } catch (RemoteException e) { } } + /** @hide */ + public void startSession(Bundle args) { + startSession(args, 0); + } + @Override public void onCreate() { super.onCreate(); @@ -163,8 +174,8 @@ public class VoiceInteractionService extends Service { /** * Called during service initialization to tell you when the system is ready * to receive interaction from it. You should generally do initialization here - * rather than in {@link #onCreate()}. Methods such as {@link #startSession(Bundle)} and - * {@link #createAlwaysOnHotwordDetector(String, Locale, android.service.voice.AlwaysOnHotwordDetector.Callback)} + * rather than in {@link #onCreate}. Methods such as {@link #startSession} and + * {@link #createAlwaysOnHotwordDetector} * will not be operational until this point. */ public void onReady() { diff --git a/core/java/android/service/voice/VoiceInteractionServiceInfo.java b/core/java/android/service/voice/VoiceInteractionServiceInfo.java index e6e9413..ebc7507 100644 --- a/core/java/android/service/voice/VoiceInteractionServiceInfo.java +++ b/core/java/android/service/voice/VoiceInteractionServiceInfo.java @@ -99,6 +99,10 @@ public class VoiceInteractionServiceInfo { mParseError = "No sessionService specified"; return; } + if (mRecognitionService == null) { + mParseError = "No recognitionService specified"; + return; + } /* Not yet time if (mRecognitionService == null) { mParseError = "No recogitionService specified"; diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 19d14bf..a3a2ca1 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -50,7 +50,6 @@ import com.android.internal.os.SomeArgs; import java.lang.ref.WeakReference; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; /** * An active voice interaction session, providing a facility for the implementation @@ -91,7 +90,6 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>(); final Insets mTmpInsets = new Insets(); - final int[] mTmpLocation = new int[2]; final WeakReference<VoiceInteractionSession> mWeakRef = new WeakReference<VoiceInteractionSession>(this); @@ -153,6 +151,12 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() { @Override + public void handleAssist(Bundle assistBundle) { + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_HANDLE_ASSIST, + assistBundle)); + } + + @Override public void taskStarted(Intent intent, int taskId) { mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_STARTED, taskId, intent)); @@ -279,6 +283,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { static final int MSG_TASK_FINISHED = 101; static final int MSG_CLOSE_SYSTEM_DIALOGS = 102; static final int MSG_DESTROY = 103; + static final int MSG_HANDLE_ASSIST = 104; class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback { @Override @@ -341,6 +346,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { if (DEBUG) Log.d(TAG, "doDestroy"); doDestroy(); break; + case MSG_HANDLE_ASSIST: + if (DEBUG) Log.d(TAG, "onHandleAssist: " + (Bundle)msg.obj); + onHandleAssist((Bundle) msg.obj); + break; } } @@ -441,10 +450,11 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } } - void doCreate(IVoiceInteractionManagerService service, IBinder token, Bundle args) { + void doCreate(IVoiceInteractionManagerService service, IBinder token, Bundle args, + int startFlags) { mSystemService = service; mToken = token; - onCreate(args); + onCreate(args, startFlags); } void doDestroy() { @@ -585,12 +595,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { } } - /** - * Initiatize a new session. - * - * @param args The arguments that were supplied to - * {@link VoiceInteractionService#startSession VoiceInteractionService.startSession}. - */ + /** @hide */ public void onCreate(Bundle args) { mTheme = mTheme != 0 ? mTheme : com.android.internal.R.style.Theme_DeviceDefault_VoiceInteractionSession; @@ -598,14 +603,26 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { Context.LAYOUT_INFLATER_SERVICE); mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme, mCallbacks, this, mDispatcherState, - WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.TOP, true); + WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true); mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); initViews(); - mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT); + mWindow.getWindow().setLayout(MATCH_PARENT, MATCH_PARENT); mWindow.setToken(mToken); } /** + * Initiatize a new session. + * + * @param args The arguments that were supplied to + * {@link VoiceInteractionService#startSession VoiceInteractionService.startSession}. + * @param startFlags The start flags originally provided to + * {@link VoiceInteractionService#startSession VoiceInteractionService.startSession}. + */ + public void onCreate(Bundle args, int startFlags) { + onCreate(args); + } + + /** * Last callback to the session as it is being finished. */ public void onDestroy() { @@ -622,10 +639,13 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { mContentFrame.removeAllViews(); mContentFrame.addView(view, new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); + ViewGroup.LayoutParams.MATCH_PARENT)); } + public void onHandleAssist(Bundle assistBundle) { + } + public boolean onKeyDown(int keyCode, KeyEvent event) { return false; } @@ -657,19 +677,19 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { /** * Compute the interesting insets into your UI. The default implementation - * uses the entire window frame as the insets. The default touchable - * insets are {@link Insets#TOUCHABLE_INSETS_FRAME}. + * sets {@link Insets#contentInsets outInsets.contentInsets.top} to the height + * of the window, meaning it should not adjust content underneath. The default touchable + * insets are {@link Insets#TOUCHABLE_INSETS_FRAME}, meaning it consumes all touch + * events within its window frame. * * @param outInsets Fill in with the current UI insets. */ public void onComputeInsets(Insets outInsets) { - int[] loc = mTmpLocation; - View decor = getWindow().getWindow().getDecorView(); - decor.getLocationInWindow(loc); - outInsets.contentInsets.top = 0; outInsets.contentInsets.left = 0; - outInsets.contentInsets.right = 0; outInsets.contentInsets.bottom = 0; + outInsets.contentInsets.right = 0; + View decor = getWindow().getWindow().getDecorView(); + outInsets.contentInsets.top = decor.getHeight(); outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME; outInsets.touchableRegion.setEmpty(); } diff --git a/core/java/android/service/voice/VoiceInteractionSessionService.java b/core/java/android/service/voice/VoiceInteractionSessionService.java index e793849..008d55f 100644 --- a/core/java/android/service/voice/VoiceInteractionSessionService.java +++ b/core/java/android/service/voice/VoiceInteractionSessionService.java @@ -40,9 +40,9 @@ public abstract class VoiceInteractionSessionService extends Service { VoiceInteractionSession mSession; IVoiceInteractionSessionService mInterface = new IVoiceInteractionSessionService.Stub() { - public void newSession(IBinder token, Bundle args) { - mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOO(MSG_NEW_SESSION, - token, args)); + public void newSession(IBinder token, Bundle args, int startFlags) { + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO(MSG_NEW_SESSION, + startFlags, token, args)); } }; @@ -54,7 +54,7 @@ public abstract class VoiceInteractionSessionService extends Service { SomeArgs args = (SomeArgs)msg.obj; switch (msg.what) { case MSG_NEW_SESSION: - doNewSession((IBinder)args.arg1, (Bundle)args.arg2); + doNewSession((IBinder)args.arg1, (Bundle)args.arg2, args.argi1); break; } } @@ -76,7 +76,7 @@ public abstract class VoiceInteractionSessionService extends Service { return mInterface.asBinder(); } - void doNewSession(IBinder token, Bundle args) { + void doNewSession(IBinder token, Bundle args, int startFlags) { if (mSession != null) { mSession.doDestroy(); mSession = null; @@ -84,7 +84,7 @@ public abstract class VoiceInteractionSessionService extends Service { mSession = onNewSession(args); try { mSystemService.deliverNewSession(token, mSession.mSession, mSession.mInteractor); - mSession.doCreate(mSystemService, token, args); + mSession.doCreate(mSystemService, token, args, startFlags); } catch (RemoteException e) { } } diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index 5a10524..6d90420 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -26,7 +26,7 @@ import android.service.voice.IVoiceInteractionService; import android.service.voice.IVoiceInteractionSession; interface IVoiceInteractionManagerService { - void startSession(IVoiceInteractionService service, in Bundle sessionArgs); + void startSession(IVoiceInteractionService service, in Bundle sessionArgs, int flags); boolean deliverNewSession(IBinder token, IVoiceInteractionSession session, IVoiceInteractor interactor); int startVoiceActivity(IBinder token, in Intent intent, String resolvedType); diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java index 65b56ec..64e1d10 100644 --- a/core/java/com/android/internal/util/DumpUtils.java +++ b/core/java/com/android/internal/util/DumpUtils.java @@ -35,13 +35,14 @@ public final class DumpUtils { * trying to acquire, we use a short timeout to avoid deadlocks. The process * is inelegant but this function is only used for debugging purposes. */ - public static void dumpAsync(Handler handler, final Dump dump, PrintWriter pw, long timeout) { + public static void dumpAsync(Handler handler, final Dump dump, PrintWriter pw, + final String prefix, long timeout) { final StringWriter sw = new StringWriter(); if (handler.runWithScissors(new Runnable() { @Override public void run() { PrintWriter lpw = new FastPrintWriter(sw); - dump.dump(lpw); + dump.dump(lpw, prefix); lpw.close(); } }, timeout)) { @@ -52,6 +53,6 @@ public final class DumpUtils { } public interface Dump { - void dump(PrintWriter pw); + void dump(PrintWriter pw, String prefix); } } diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml index 57041fd..3fa24c2 100644 --- a/core/res/res/values/themes_material.xml +++ b/core/res/res/values/themes_material.xml @@ -972,8 +972,12 @@ please see themes_device_defaults.xml. {@link android.service.voice.VoiceInteractionSession} class. this inherits from Theme.Panel, but sets up appropriate animations and a few custom attributes. --> - <style name="Theme.Material.VoiceInteractionSession" parent="Theme.Material.Light.Panel"> - <item name="windowAnimationStyle">@style/Animation.VoiceInteractionSession</item> + <style name="Theme.Material.VoiceInteractionSession" + parent="Theme.Material.Light.NoActionBar.TranslucentDecor"> + <item name="windowBackground">@color/transparent</item> + <item name="colorBackgroundCacheHint">@null</item> + <item name="windowIsTranslucent">true</item> + <item name="windowAnimationStyle">@style/Animation</item> </style> <!-- Theme for the search input bar. --> diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c4718b8..511347e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -65,6 +65,7 @@ import com.android.internal.app.ProcessMap; import com.android.internal.app.ProcessStats; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BatteryStatsImpl; +import com.android.internal.os.IResultReceiver; import com.android.internal.os.ProcessCpuTracker; import com.android.internal.os.TransferPipe; import com.android.internal.os.Zygote; @@ -439,23 +440,28 @@ public final class ActivityManagerService extends ActivityManagerNative public final Bundle extras; public final Intent intent; public final String hint; + public final IResultReceiver receiver; public final int userHandle; public boolean haveResult = false; public Bundle result = null; public PendingAssistExtras(ActivityRecord _activity, Bundle _extras, Intent _intent, - String _hint, int _userHandle) { + String _hint, IResultReceiver _receiver, int _userHandle) { activity = _activity; extras = _extras; intent = _intent; hint = _hint; + receiver = _receiver; userHandle = _userHandle; } @Override public void run() { Slog.w(TAG, "getAssistContextExtras failed: timeout retrieving from " + activity); - synchronized (this) { - haveResult = true; - notifyAll(); + synchronized (ActivityManagerService.this) { + synchronized (this) { + haveResult = true; + notifyAll(); + } + pendingAssistExtrasTimedOutLocked(this); } } } @@ -9980,8 +9986,9 @@ public final class ActivityManagerService extends ActivityManagerNative return true; } + @Override public Bundle getAssistContextExtras(int requestType) { - PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, + PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null, UserHandle.getCallingUserId()); if (pae == null) { return null; @@ -9993,19 +10000,22 @@ public final class ActivityManagerService extends ActivityManagerNative } catch (InterruptedException e) { } } - if (pae.result != null) { - pae.extras.putBundle(Intent.EXTRA_ASSIST_CONTEXT, pae.result); - } } synchronized (this) { + buildAssistBundleLocked(pae, pae.result); mPendingAssistExtras.remove(pae); mHandler.removeCallbacks(pae); } return pae.extras; } + @Override + public void requestAssistContextExtras(int requestType, IResultReceiver receiver) { + enqueueAssistContext(requestType, null, null, receiver, UserHandle.getCallingUserId()); + } + private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint, - int userHandle) { + IResultReceiver receiver, int userHandle) { enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO, "getAssistContextExtras()"); PendingAssistExtras pae; @@ -10025,7 +10035,7 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, "getAssistContextExtras failed: request process same as " + activity); return null; } - pae = new PendingAssistExtras(activity, extras, intent, hint, userHandle); + pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, userHandle); try { activity.app.thread.requestAssistContextExtras(activity.appToken, pae, requestType); @@ -10039,13 +10049,33 @@ public final class ActivityManagerService extends ActivityManagerNative } } + void pendingAssistExtrasTimedOutLocked(PendingAssistExtras pae) { + mPendingAssistExtras.remove(pae); + if (pae.receiver != null) { + // Caller wants result sent back to them. + try { + pae.receiver.send(0, null); + } catch (RemoteException e) { + } + } + } + + private void buildAssistBundleLocked(PendingAssistExtras pae, Bundle result) { + if (result != null) { + pae.extras.putBundle(Intent.EXTRA_ASSIST_CONTEXT, result); + } + if (pae.hint != null) { + pae.extras.putBoolean(pae.hint, true); + } + } + public void reportAssistContextExtras(IBinder token, Bundle extras) { PendingAssistExtras pae = (PendingAssistExtras)token; synchronized (pae) { pae.result = extras; pae.haveResult = true; pae.notifyAll(); - if (pae.intent == null) { + if (pae.intent == null && pae.receiver == null) { // Caller is just waiting for the result. return; } @@ -10053,17 +10083,23 @@ public final class ActivityManagerService extends ActivityManagerNative // We are now ready to launch the assist activity. synchronized (this) { + buildAssistBundleLocked(pae, extras); boolean exists = mPendingAssistExtras.remove(pae); mHandler.removeCallbacks(pae); if (!exists) { // Timed out. return; } + if (pae.receiver != null) { + // Caller wants result sent back to them. + try { + pae.receiver.send(0, pae.extras); + } catch (RemoteException e) { + } + return; + } } - pae.intent.replaceExtras(extras); - if (pae.hint != null) { - pae.intent.putExtra(pae.hint, true); - } + pae.intent.replaceExtras(pae.extras); pae.intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); @@ -10076,7 +10112,7 @@ public final class ActivityManagerService extends ActivityManagerNative } public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle) { - return enqueueAssistContext(requestType, intent, hint, userHandle) != null; + return enqueueAssistContext(requestType, intent, hint, null, userHandle) != null; } public void registerProcessObserver(IProcessObserver observer) { diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java index 5b6f35b..af9f456 100644 --- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java +++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java @@ -355,7 +355,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter { if (mWindow != null) { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); ipw.increaseIndent(); - DumpUtils.dumpAsync(mUiHandler, mWindow, ipw, 200); + DumpUtils.dumpAsync(mUiHandler, mWindow, ipw, "", 200); } } diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java index 9ca5fda..3f4eab9 100644 --- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java +++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java @@ -153,7 +153,7 @@ final class OverlayDisplayWindow implements DumpUtils.Dump { } @Override - public void dump(PrintWriter pw) { + public void dump(PrintWriter pw, String prefix) { pw.println("mWindowVisible=" + mWindowVisible); pw.println("mWindowX=" + mWindowX); pw.println("mWindowY=" + mWindowY); diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java index c939861..f163555 100644 --- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java +++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java @@ -123,7 +123,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { pw.println("mDisplayController:"); final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); ipw.increaseIndent(); - DumpUtils.dumpAsync(getHandler(), mDisplayController, ipw, 200); + DumpUtils.dumpAsync(getHandler(), mDisplayController, ipw, "", 200); } } diff --git a/services/core/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java index dbb59b2..31c1eea 100644 --- a/services/core/java/com/android/server/display/WifiDisplayController.java +++ b/services/core/java/com/android/server/display/WifiDisplayController.java @@ -209,7 +209,7 @@ final class WifiDisplayController implements DumpUtils.Dump { } @Override - public void dump(PrintWriter pw) { + public void dump(PrintWriter pw, String prefix) { pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting); pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled); pw.println("mWfdEnabled=" + mWfdEnabled); diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java index 4521c28..458928f 100644 --- a/services/core/java/com/android/server/dreams/DreamManagerService.java +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -137,10 +137,10 @@ public final class DreamManagerService extends SystemService { DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() { @Override - public void dump(PrintWriter pw) { + public void dump(PrintWriter pw, String prefix) { mController.dump(pw); } - }, pw, 200); + }, pw, "", 200); } private boolean isDreamingInternal() { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 5bb193a..ff274b6 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -3554,7 +3554,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop + mOverscanScreenHeight; } - } else if (attrs.type == TYPE_INPUT_METHOD) { + } else if (attrs.type == TYPE_INPUT_METHOD || attrs.type == TYPE_VOICE_INTERACTION) { pf.left = df.left = of.left = cf.left = vf.left = mDockLeft; pf.top = df.top = of.top = cf.top = vf.top = mDockTop; pf.right = df.right = of.right = cf.right = vf.right = mDockRight; @@ -3936,7 +3936,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private void offsetInputMethodWindowLw(WindowState win) { - int top = win.getContentFrameLw().top; + int top = win.getDisplayFrameLw().top; top += win.getGivenContentInsetsLw().top; if (mContentBottom > top) { mContentBottom = top; @@ -3955,36 +3955,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private void offsetVoiceInputWindowLw(WindowState win) { - final int gravity = win.getAttrs().gravity; - switch (gravity&((Gravity.AXIS_PULL_BEFORE|Gravity.AXIS_PULL_AFTER) - << Gravity.AXIS_X_SHIFT)) { - case Gravity.AXIS_PULL_BEFORE<<Gravity.AXIS_X_SHIFT: { - int right = win.getContentFrameLw().right - win.getGivenContentInsetsLw().right; - if (mVoiceContentLeft < right) { - mVoiceContentLeft = right; - } - } break; - case Gravity.AXIS_PULL_AFTER<<Gravity.AXIS_X_SHIFT: { - int left = win.getContentFrameLw().left - win.getGivenContentInsetsLw().left; - if (mVoiceContentRight < left) { - mVoiceContentRight = left; - } - } break; - } - switch (gravity&((Gravity.AXIS_PULL_BEFORE|Gravity.AXIS_PULL_AFTER) - << Gravity.AXIS_Y_SHIFT)) { - case Gravity.AXIS_PULL_BEFORE<<Gravity.AXIS_Y_SHIFT: { - int bottom = win.getContentFrameLw().bottom - win.getGivenContentInsetsLw().bottom; - if (mVoiceContentTop < bottom) { - mVoiceContentTop = bottom; - } - } break; - case Gravity.AXIS_PULL_AFTER<<Gravity.AXIS_Y_SHIFT: { - int top = win.getContentFrameLw().top - win.getGivenContentInsetsLw().top; - if (mVoiceContentBottom < top) { - mVoiceContentBottom = top; - } - } break; + int top = win.getDisplayFrameLw().top; + top += win.getGivenContentInsetsLw().top; + if (mVoiceContentBottom > top) { + mVoiceContentBottom = top; } } @@ -6385,9 +6359,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (mStatusBar != null) { pw.print(prefix); pw.print("mStatusBar="); - pw.println(mStatusBar); - pw.print(prefix); pw.print("isStatusBarKeyguard="); - pw.print(isStatusBarKeyguard()); + pw.print(mStatusBar); pw.print(" isStatusBarKeyguard="); + pw.println(isStatusBarKeyguard()); } if (mNavigationBar != null) { pw.print(prefix); pw.print("mNavigationBar="); diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index c0d54e1..231a6bd 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -1130,32 +1130,34 @@ public class AppTransition implements Dump { } @Override - public void dump(PrintWriter pw) { - pw.print(" " + this); - pw.print(" mAppTransitionState="); pw.println(appStateToString()); + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.println(this); + pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString()); if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) { - pw.print(" mNextAppTransitionType="); pw.println(transitTypeToString()); + pw.print(prefix); pw.print("mNextAppTransitionType="); + pw.println(transitTypeToString()); } switch (mNextAppTransitionType) { case NEXT_TRANSIT_TYPE_CUSTOM: - pw.print(" mNextAppTransitionPackage="); + pw.print(prefix); pw.print("mNextAppTransitionPackage="); pw.println(mNextAppTransitionPackage); - pw.print(" mNextAppTransitionEnter=0x"); + pw.print(prefix); pw.print("mNextAppTransitionEnter=0x"); pw.print(Integer.toHexString(mNextAppTransitionEnter)); pw.print(" mNextAppTransitionExit=0x"); pw.println(Integer.toHexString(mNextAppTransitionExit)); break; case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE: - pw.print(" mNextAppTransitionPackage="); + pw.print(prefix); pw.print("mNextAppTransitionPackage="); pw.println(mNextAppTransitionPackage); - pw.print(" mNextAppTransitionInPlace=0x"); + pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x"); pw.print(Integer.toHexString(mNextAppTransitionInPlace)); break; case NEXT_TRANSIT_TYPE_SCALE_UP: - pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX); + pw.print(prefix); pw.print("mNextAppTransitionStartX="); + pw.print(mNextAppTransitionStartX); pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY); - pw.print(" mNextAppTransitionStartWidth="); + pw.print(prefix); pw.print("mNextAppTransitionStartWidth="); pw.print(mNextAppTransitionStartWidth); pw.print(" mNextAppTransitionStartHeight="); pw.println(mNextAppTransitionStartHeight); @@ -1164,22 +1166,23 @@ public class AppTransition implements Dump { case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN: case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP: case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: - pw.print(" mNextAppTransitionThumbnail="); + pw.print(prefix); pw.print("mNextAppTransitionThumbnail="); pw.print(mNextAppTransitionThumbnail); pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX); pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY); - pw.print(" mNextAppTransitionStartWidth="); + pw.print(prefix); pw.print("mNextAppTransitionStartWidth="); pw.print(mNextAppTransitionStartWidth); pw.print(" mNextAppTransitionStartHeight="); pw.println(mNextAppTransitionStartHeight); - pw.print(" mNextAppTransitionScaleUp="); pw.println(mNextAppTransitionScaleUp); + pw.print(prefix); pw.print("mNextAppTransitionScaleUp="); + pw.println(mNextAppTransitionScaleUp); break; } if (mNextAppTransitionCallback != null) { - pw.print(" mNextAppTransitionCallback="); - pw.println(mNextAppTransitionCallback); + pw.print(prefix); pw.print("mNextAppTransitionCallback="); + pw.println(mNextAppTransitionCallback); } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 02a4f4d..8e217b9 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -11058,7 +11058,7 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition); pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation); pw.println(" mLayoutToAnim:"); - mAppTransition.dump(pw); + mAppTransition.dump(pw, " "); } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index c32ba67..fd990d7 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -129,12 +129,14 @@ public class VoiceInteractionManagerService extends SystemService { } public void initForUser(int userHandle) { - if (DEBUG) Slog.i(TAG, "initForUser user=" + userHandle); + if (DEBUG) Slog.d(TAG, "**************** initForUser user=" + userHandle); String curInteractorStr = Settings.Secure.getStringForUser( mContext.getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle); ComponentName curRecognizer = getCurRecognizer(userHandle); VoiceInteractionServiceInfo curInteractorInfo = null; + if (DEBUG) Slog.d(TAG, "curInteractorStr=" + curInteractorStr + + " curRecognizer=" + curRecognizer); if (curInteractorStr == null && curRecognizer != null && !ActivityManager.isLowRamDeviceStatic()) { // If there is no interactor setting, that means we are upgrading @@ -148,6 +150,8 @@ public class VoiceInteractionManagerService extends SystemService { // Looks good! We'll apply this one. To make it happen, we clear the // recognizer so that we don't think we have anything set and will // re-apply the settings. + if (DEBUG) Slog.d(TAG, "No set interactor, found avail: " + + curInteractorInfo.getServiceInfo().name); curRecognizer = null; } } @@ -156,6 +160,7 @@ public class VoiceInteractionManagerService extends SystemService { // enabled; if it is, turn it off. if (ActivityManager.isLowRamDeviceStatic() && curInteractorStr != null) { if (!TextUtils.isEmpty(curInteractorStr)) { + if (DEBUG) Slog.d(TAG, "Svelte device; disabling interactor"); setCurInteractor(null, userHandle); curInteractorStr = ""; } @@ -178,8 +183,11 @@ public class VoiceInteractionManagerService extends SystemService { } // If the apps for the currently set components still exist, then all is okay. if (recognizerInfo != null && (curInteractor == null || interactorInfo != null)) { + if (DEBUG) Slog.d(TAG, "Current interactor/recognizer okay, done!"); return; } + if (DEBUG) Slog.d(TAG, "Bad recognizer (" + recognizerInfo + ") or interactor (" + + interactorInfo + ")"); } // Initializing settings, look for an interactor first (but only on non-svelte). @@ -316,7 +324,7 @@ public class VoiceInteractionManagerService extends SystemService { if (TextUtils.isEmpty(curInteractor)) { return null; } - if (DEBUG) Slog.i(TAG, "getCurInteractor curInteractor=" + curInteractor + if (DEBUG) Slog.d(TAG, "getCurInteractor curInteractor=" + curInteractor + " user=" + userHandle); return ComponentName.unflattenFromString(curInteractor); } @@ -325,7 +333,7 @@ public class VoiceInteractionManagerService extends SystemService { Settings.Secure.putStringForUser(mContext.getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE, comp != null ? comp.flattenToShortString() : "", userHandle); - if (DEBUG) Slog.i(TAG, "setCurInteractor comp=" + comp + if (DEBUG) Slog.d(TAG, "setCurInteractor comp=" + comp + " user=" + userHandle); } @@ -363,7 +371,7 @@ public class VoiceInteractionManagerService extends SystemService { if (TextUtils.isEmpty(curRecognizer)) { return null; } - if (DEBUG) Slog.i(TAG, "getCurRecognizer curRecognizer=" + curRecognizer + if (DEBUG) Slog.d(TAG, "getCurRecognizer curRecognizer=" + curRecognizer + " user=" + userHandle); return ComponentName.unflattenFromString(curRecognizer); } @@ -372,12 +380,12 @@ public class VoiceInteractionManagerService extends SystemService { Settings.Secure.putStringForUser(mContext.getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE, comp != null ? comp.flattenToShortString() : "", userHandle); - if (DEBUG) Slog.i(TAG, "setCurRecognizer comp=" + comp + if (DEBUG) Slog.d(TAG, "setCurRecognizer comp=" + comp + " user=" + userHandle); } @Override - public void startSession(IVoiceInteractionService service, Bundle args) { + public void startSession(IVoiceInteractionService service, Bundle args, int flags) { synchronized (this) { if (mImpl == null || mImpl.mService == null || service.asBinder() != mImpl.mService.asBinder()) { @@ -388,7 +396,7 @@ public class VoiceInteractionManagerService extends SystemService { final int callingUid = Binder.getCallingUid(); final long caller = Binder.clearCallingIdentity(); try { - mImpl.startSessionLocked(callingPid, callingUid, args); + mImpl.startSessionLocked(callingPid, callingUid, args, flags); } finally { Binder.restoreCallingIdentity(caller); } @@ -692,7 +700,7 @@ public class VoiceInteractionManagerService extends SystemService { @Override public void onSomePackagesChanged() { int userHandle = getChangingUserId(); - if (DEBUG) Slog.i(TAG, "onSomePackagesChanged user=" + userHandle); + if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle); ComponentName curInteractor = getCurInteractor(userHandle); ComponentName curRecognizer = getCurRecognizer(userHandle); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index b36b611..e80f702 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -43,6 +43,7 @@ import android.view.IWindowManager; import android.view.WindowManager; import com.android.internal.app.IVoiceInteractor; +import com.android.internal.os.IResultReceiver; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -103,13 +104,33 @@ class VoiceInteractionManagerServiceImpl { final class SessionConnection implements ServiceConnection { final IBinder mToken = new Binder(); final Bundle mArgs; + final int mFlags; boolean mBound; IVoiceInteractionSessionService mService; IVoiceInteractionSession mSession; IVoiceInteractor mInteractor; + boolean mHaveAssistData; + Bundle mAssistData; - SessionConnection(Bundle args) { + final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() { + @Override + public void send(int resultCode, Bundle resultData) throws RemoteException { + synchronized (mLock) { + mHaveAssistData = true; + mAssistData = resultData; + if (mSession != null) { + try { + mSession.handleAssist(resultData); + } catch (RemoteException e) { + } + } + } + } + }; + + SessionConnection(Bundle args, int flags) { mArgs = args; + mFlags = flags; Intent serviceIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE); serviceIntent.setComponent(mSessionComponentName); mBound = mContext.bindServiceAsUser(serviceIntent, this, @@ -121,6 +142,14 @@ class VoiceInteractionManagerServiceImpl { } catch (RemoteException e) { Slog.w(TAG, "Failed adding window token", e); } + if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) { + try { + mAm.requestAssistContextExtras(0, mAssistReceiver); + } catch (RemoteException e) { + } + } else { + mHaveAssistData = true; + } } else { Slog.w(TAG, "Failed binding to voice interaction session service " + mComponent); } @@ -132,7 +161,7 @@ class VoiceInteractionManagerServiceImpl { mService = IVoiceInteractionSessionService.Stub.asInterface(service); if (mActiveSession == this) { try { - mService.newSession(mToken, mArgs); + mService.newSession(mToken, mArgs, mFlags); } catch (RemoteException e) { Slog.w(TAG, "Failed adding window token", e); } @@ -176,12 +205,17 @@ class VoiceInteractionManagerServiceImpl { public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("mToken="); pw.println(mToken); pw.print(prefix); pw.print("mArgs="); pw.println(mArgs); + pw.print(prefix); pw.print("mFlags=0x"); pw.println(Integer.toHexString(mFlags)); pw.print(prefix); pw.print("mBound="); pw.println(mBound); if (mBound) { pw.print(prefix); pw.print("mService="); pw.println(mService); pw.print(prefix); pw.print("mSession="); pw.println(mSession); pw.print(prefix); pw.print("mInteractor="); pw.println(mInteractor); } + pw.print(prefix); pw.print("mHaveAssistData="); pw.println(mHaveAssistData); + if (mHaveAssistData) { + pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData); + } } }; @@ -222,12 +256,12 @@ class VoiceInteractionManagerServiceImpl { mContext.registerReceiver(mBroadcastReceiver, filter, null, handler); } - public void startSessionLocked(int callingPid, int callingUid, Bundle args) { + public void startSessionLocked(int callingPid, int callingUid, Bundle args, int flags) { if (mActiveSession != null) { mActiveSession.cancel(); mActiveSession = null; } - mActiveSession = new SessionConnection(args); + mActiveSession = new SessionConnection(args, flags); } public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token, @@ -238,6 +272,12 @@ class VoiceInteractionManagerServiceImpl { } mActiveSession.mSession = session; mActiveSession.mInteractor = interactor; + if (mActiveSession.mHaveAssistData) { + try { + session.handleAssist(mActiveSession.mAssistData); + } catch (RemoteException e) { + } + } return true; } diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml index 06d31a4..adf572c 100644 --- a/tests/VoiceInteraction/AndroidManifest.xml +++ b/tests/VoiceInteraction/AndroidManifest.xml @@ -12,11 +12,19 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> - <activity android:name="SettingsActivity" - android:label="Voice Interaction Settings" + <activity android:name="AssistProxyActivity" + android:label="Test Assist Proxy" + android:theme="@android:style/Theme.NoDisplay" android:excludeFromRecents="true" android:noHistory="true"> <intent-filter> + <action android:name="android.intent.action.ASSIST" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + <activity android:name="SettingsActivity" + android:label="Voice Interaction Settings"> + <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> @@ -44,7 +52,7 @@ <meta-data android:name="android.speech" android:resource="@xml/recognition_service" /> </service> <activity android:name="TestInteractionActivity" android:label="Voice Interaction Target" - android:theme="@android:style/Theme.Material.Light.Voice"> + android:theme="@android:style/Theme.Material.Light"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> diff --git a/tests/VoiceInteraction/res/layout/test_interaction.xml b/tests/VoiceInteraction/res/layout/test_interaction.xml index d55736f..c4e280e 100644 --- a/tests/VoiceInteraction/res/layout/test_interaction.xml +++ b/tests/VoiceInteraction/res/layout/test_interaction.xml @@ -32,7 +32,6 @@ android:layout_weight="1" android:layout_marginTop="16dp" android:textAppearance="?android:attr/textAppearanceMedium" - android:textColor="#ffffffff" /> <Button android:id="@+id/complete" diff --git a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml index 002f350..1057176 100644 --- a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml +++ b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml @@ -15,24 +15,46 @@ --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="match_parent" - android:fitsSystemWindows="true"> + android:layout_width="match_parent" + android:layout_height="match_parent"> - <FrameLayout android:layout_width="fill_parent" + <com.android.test.voiceinteraction.AssistVisualizer android:id="@+id/assist_visualizer" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" - android:padding="8dp"> + android:fitsSystemWindows="true"> - <LinearLayout android:id="@+id/content" - android:layout_width="fill_parent" - android:layout_height="match_parent" + <FrameLayout android:id="@+id/top_content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="top" + android:orientation="vertical" + android:background="#ffffffff" + android:elevation="8dp" + > + + <Button android:id="@+id/start" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="top|right" + android:text="@string/start" + /> + + </FrameLayout> + + <LinearLayout android:id="@+id/bottom_content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" android:orientation="vertical" android:background="#ffffffff" android:elevation="8dp" > <TextView android:id="@+id/text" - android:layout_width="fill_parent" + android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:textAppearance="?android:attr/textAppearanceMedium" @@ -40,11 +62,6 @@ <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> - <Button android:id="@+id/start" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/start" - /> <Button android:id="@+id/confirm" android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java new file mode 100644 index 0000000..fc04ff5 --- /dev/null +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.test.voiceinteraction; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +public class AssistProxyActivity extends Activity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + finish(); + Intent intent = new Intent(this, MainInteractionService.class); + intent.setAction(Intent.ACTION_ASSIST); + intent.putExtras(getIntent()); + startService(new Intent(this, MainInteractionService.class)); + } +} diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java new file mode 100644 index 0000000..5d5ae2f --- /dev/null +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.test.voiceinteraction; + +import android.annotation.Nullable; +import android.app.AssistData; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; + +import java.util.ArrayList; + +public class AssistVisualizer extends View { + static final String TAG = "AssistVisualizer"; + + AssistData mAssistData; + final Paint mFramePaint = new Paint(); + final ArrayList<Rect> mTextRects = new ArrayList<>(); + final int[] mTmpLocation = new int[2]; + + public AssistVisualizer(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + setWillNotDraw(false); + mFramePaint.setColor(0xffff0000); + mFramePaint.setStyle(Paint.Style.STROKE); + mFramePaint.setStrokeWidth(0); + } + + public void setAssistData(AssistData ad) { + mAssistData = ad; + mTextRects.clear(); + final int N = ad.getWindowCount(); + if (N > 0) { + AssistData.ViewNode window = new AssistData.ViewNode(); + for (int i=0; i<N; i++) { + ad.getWindowAt(i, window); + buildTextRects(window, 0, 0); + } + } + } + + void buildTextRects(AssistData.ViewNode root, int parentLeft, int parentTop) { + if (root.getVisibility() != View.VISIBLE) { + return; + } + int left = parentLeft+root.getLeft(); + int top = parentTop+root.getTop(); + Log.d(TAG, "View " + root.getClassName() + ": " + left + ", " + top); + if (root.getText() != null) { + Rect r = new Rect(left, top, left+root.getWidth(), top+root.getHeight()); + Log.d(TAG, "Text Rect " + r.toShortString() + ": " + root.getText()); + mTextRects.add(r); + } + final int N = root.getChildCount(); + if (N > 0) { + left -= root.getScrollX(); + top -= root.getScrollY(); + AssistData.ViewNode child = new AssistData.ViewNode(); + for (int i=0; i<N; i++) { + root.getChildAt(i, child); + buildTextRects(child, left, top); + } + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + getLocationOnScreen(mTmpLocation); + final int N = mTextRects.size(); + for (int i=0; i<N; i++) { + Rect r = mTextRects.get(i); + canvas.drawRect(r.left-mTmpLocation[0], r.top-mTmpLocation[1], + r.right-mTmpLocation[0], r.bottom-mTmpLocation[1], mFramePaint); + } + } +} diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java index 4639114..2cab3ea 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java @@ -16,6 +16,7 @@ package com.android.test.voiceinteraction; +import android.content.ComponentName; import android.content.Intent; import android.os.Bundle; import android.service.voice.AlwaysOnHotwordDetector; @@ -74,9 +75,19 @@ public class MainInteractionService extends VoiceInteractionService { @Override public int onStartCommand(Intent intent, int flags, int startId) { - Bundle args = new Bundle(); - args.putParcelable("intent", new Intent(this, TestInteractionActivity.class)); - startSession(args); + if (isActiveService(this, new ComponentName(this, getClass()))) { + Bundle args = new Bundle(); + args.putParcelable("intent", new Intent(this, TestInteractionActivity.class)); + args.putBundle("assist", intent.getExtras()); + Bundle assistContext = intent.getBundleExtra(Intent.EXTRA_ASSIST_CONTEXT); + int startFlags = 0; + if (assistContext == null) { + startFlags |= START_WITH_ASSIST; + } + startSession(args, startFlags); + } else { + Log.w(TAG, "Not starting -- not current voice interaction service"); + } stopSelf(startId); return START_NOT_STICKY; } diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java index d20906e..1aeb98a 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java @@ -16,6 +16,7 @@ package com.android.test.voiceinteraction; +import android.app.AssistData; import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -31,12 +32,17 @@ public class MainInteractionSession extends VoiceInteractionSession Intent mStartIntent; View mContentView; + AssistVisualizer mAssistVisualizer; + View mTopContent; + View mBottomContent; TextView mText; Button mStartButton; Button mConfirmButton; Button mCompleteButton; Button mAbortButton; + AssistData mAssistData; + static final int STATE_IDLE = 0; static final int STATE_LAUNCHING = 1; static final int STATE_CONFIRM = 2; @@ -52,15 +58,25 @@ public class MainInteractionSession extends VoiceInteractionSession } @Override - public void onCreate(Bundle args) { + public void onCreate(Bundle args, int startFlags) { super.onCreate(args); showWindow(); mStartIntent = args.getParcelable("intent"); + Bundle assist = args.getBundle("assist"); + if (assist != null) { + parseAssistData(assist); + } } @Override public View onCreateContentView() { mContentView = getLayoutInflater().inflate(R.layout.voice_interaction_session, null); + mAssistVisualizer = (AssistVisualizer)mContentView.findViewById(R.id.assist_visualizer); + if (mAssistData != null) { + mAssistVisualizer.setAssistData(mAssistData); + } + mTopContent = mContentView.findViewById(R.id.top_content); + mBottomContent = mContentView.findViewById(R.id.bottom_content); mText = (TextView)mContentView.findViewById(R.id.text); mStartButton = (Button)mContentView.findViewById(R.id.start); mStartButton.setOnClickListener(this); @@ -74,7 +90,34 @@ public class MainInteractionSession extends VoiceInteractionSession return mContentView; } + @Override + public void onHandleAssist(Bundle assistBundle) { + if (assistBundle != null) { + parseAssistData(assistBundle); + } else { + Log.i(TAG, "onHandleAssist: NO ASSIST BUNDLE"); + } + } + + void parseAssistData(Bundle assistBundle) { + Bundle assistContext = assistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT); + if (assistContext != null) { + mAssistData = AssistData.getAssistData(assistContext); + mAssistData.dump(); + if (mAssistVisualizer != null) { + mAssistVisualizer.setAssistData(mAssistData); + } + } + } + void updateState() { + if (mState == STATE_IDLE) { + mTopContent.setVisibility(View.VISIBLE); + mBottomContent.setVisibility(View.GONE); + } else { + mTopContent.setVisibility(View.GONE); + mBottomContent.setVisibility(View.VISIBLE); + } mStartButton.setEnabled(mState == STATE_IDLE); mConfirmButton.setEnabled(mState == STATE_CONFIRM || mState == STATE_COMMAND); mAbortButton.setEnabled(mState == STATE_ABORT_VOICE); @@ -109,6 +152,15 @@ public class MainInteractionSession extends VoiceInteractionSession } @Override + public void onComputeInsets(Insets outInsets) { + super.onComputeInsets(outInsets); + if (mState != STATE_IDLE) { + outInsets.contentInsets.top = mBottomContent.getTop(); + outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_CONTENT; + } + } + + @Override public boolean[] onGetSupportedCommands(Caller caller, String[] commands) { return new boolean[commands.length]; } diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java index 783c78e..8522cdc 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java @@ -57,11 +57,6 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis mCompleteButton = (Button)findViewById(R.id.complete); mCompleteButton.setOnClickListener(this); - // Framework should take care of these. - getWindow().setGravity(Gravity.TOP); - getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - mInteractor = getVoiceInteractor(); VoiceInteractor.ConfirmationRequest req = new VoiceInteractor.ConfirmationRequest( "This is a confirmation", null) { |