blob: 83398cf6a88f4356fc10a349a0a1ebf50a7f4b41 [file] [log] [blame]
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -07001package com.android.systemui.assist;
2
Yohei Yukawa528e4682015-09-10 22:21:04 -07003import android.annotation.NonNull;
4import android.annotation.Nullable;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -07005import android.app.ActivityManager;
6import android.app.ActivityOptions;
7import android.app.SearchManager;
8import android.content.ActivityNotFoundException;
9import android.content.ComponentName;
10import android.content.Context;
11import android.content.Intent;
Jason Monk9c7844c2017-01-18 15:21:53 -050012import android.content.pm.ActivityInfo;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070013import android.content.pm.PackageManager;
Jason Monk9c7844c2017-01-18 15:21:53 -050014import android.content.res.Configuration;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070015import android.content.res.Resources;
16import android.graphics.PixelFormat;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070017import android.os.AsyncTask;
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -080018import android.os.Binder;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070019import android.os.Bundle;
Xiyuan Xiae6de8b92015-06-06 22:18:05 -070020import android.os.Handler;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070021import android.os.RemoteException;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070022import android.os.UserHandle;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070023import android.provider.Settings;
Dianne Hackborn17f69352015-07-17 18:04:14 -070024import android.service.voice.VoiceInteractionSession;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070025import android.util.Log;
26import android.view.Gravity;
27import android.view.LayoutInflater;
28import android.view.View;
29import android.view.ViewGroup;
30import android.view.WindowManager;
31import android.widget.ImageView;
32
Adrian Roose9175082015-06-15 13:23:14 -070033import com.android.internal.app.AssistUtils;
Annie Chinecb9f3e2016-06-27 16:01:52 -070034import com.android.internal.app.IVoiceInteractionSessionListener;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070035import com.android.internal.app.IVoiceInteractionSessionShowCallback;
Kaori Katou70554e02016-08-04 17:11:07 +090036import com.android.keyguard.KeyguardUpdateMonitor;
Jason Monk9c7844c2017-01-18 15:21:53 -050037import com.android.settingslib.applications.InterestingConfigChanges;
38import com.android.systemui.ConfigurationChangedReceiver;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070039import com.android.systemui.R;
Jason Monk9c7844c2017-01-18 15:21:53 -050040import com.android.systemui.SysUiServiceProvider;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070041import com.android.systemui.statusbar.CommandQueue;
Jason Monk9c7844c2017-01-18 15:21:53 -050042import com.android.systemui.statusbar.policy.DeviceProvisionedController;
Adrian Roose9175082015-06-15 13:23:14 -070043
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070044/**
Selim Cineke70d6532015-04-24 16:46:13 -070045 * Class to manage everything related to assist in SystemUI.
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070046 */
Jason Monk9c7844c2017-01-18 15:21:53 -050047public class AssistManager implements ConfigurationChangedReceiver {
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070048
Selim Cineke70d6532015-04-24 16:46:13 -070049 private static final String TAG = "AssistManager";
Matt Casey4cff16f2019-01-14 14:56:06 -050050
51 // Note that VERBOSE logging may leak PII (e.g. transcription contents).
52 private static final boolean VERBOSE = false;
53
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070054 private static final String ASSIST_ICON_METADATA_NAME =
55 "com.android.systemui.action_assist_icon";
56
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070057 private static final long TIMEOUT_SERVICE = 2500;
58 private static final long TIMEOUT_ACTIVITY = 1000;
59
Annie Chin4c249ff2016-07-08 14:52:00 -070060 protected final Context mContext;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070061 private final WindowManager mWindowManager;
Adrian Roos4f43dc02015-06-17 16:43:38 -070062 private final AssistDisclosure mAssistDisclosure;
Jason Monk9c7844c2017-01-18 15:21:53 -050063 private final InterestingConfigChanges mInterestingConfigChanges;
Adrian Roos4f43dc02015-06-17 16:43:38 -070064
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070065 private AssistOrbContainer mView;
Jason Monk9c7844c2017-01-18 15:21:53 -050066 private final DeviceProvisionedController mDeviceProvisionedController;
Annie Chinecb9f3e2016-06-27 16:01:52 -070067 protected final AssistUtils mAssistUtils;
Rajeev Kumar3e084302017-09-25 19:08:12 -070068 private final boolean mShouldEnableOrb;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070069
70 private IVoiceInteractionSessionShowCallback mShowCallback =
71 new IVoiceInteractionSessionShowCallback.Stub() {
72
73 @Override
74 public void onFailed() throws RemoteException {
75 mView.post(mHideRunnable);
76 }
77
78 @Override
79 public void onShown() throws RemoteException {
80 mView.post(mHideRunnable);
81 }
82 };
83
84 private Runnable mHideRunnable = new Runnable() {
85 @Override
86 public void run() {
87 mView.removeCallbacks(this);
88 mView.show(false /* show */, true /* animate */);
89 }
90 };
91
Jason Monk9c7844c2017-01-18 15:21:53 -050092 public AssistManager(DeviceProvisionedController controller, Context context) {
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070093 mContext = context;
Jason Monk9c7844c2017-01-18 15:21:53 -050094 mDeviceProvisionedController = controller;
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -070095 mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Adrian Roose9175082015-06-15 13:23:14 -070096 mAssistUtils = new AssistUtils(context);
Adrian Roos4f43dc02015-06-17 16:43:38 -070097 mAssistDisclosure = new AssistDisclosure(context, new Handler());
Annie Chinecb9f3e2016-06-27 16:01:52 -070098
99 registerVoiceInteractionSessionListener();
Jason Monk3edad312017-06-05 11:33:48 -0400100 mInterestingConfigChanges = new InterestingConfigChanges(ActivityInfo.CONFIG_ORIENTATION
101 | ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_UI_MODE
102 | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS);
Jason Monk9c7844c2017-01-18 15:21:53 -0500103 onConfigurationChanged(context.getResources().getConfiguration());
Rajeev Kumar3e084302017-09-25 19:08:12 -0700104 mShouldEnableOrb = !ActivityManager.isLowRamDeviceStatic();
Annie Chinecb9f3e2016-06-27 16:01:52 -0700105 }
106
107 protected void registerVoiceInteractionSessionListener() {
108 mAssistUtils.registerVoiceInteractionSessionListener(
109 new IVoiceInteractionSessionListener.Stub() {
Matt Casey4cff16f2019-01-14 14:56:06 -0500110 @Override
111 public void onVoiceSessionShown() throws RemoteException {
112 if (VERBOSE) {
113 Log.v(TAG, "Voice open");
114 }
115 }
Annie Chinecb9f3e2016-06-27 16:01:52 -0700116
Matt Casey4cff16f2019-01-14 14:56:06 -0500117 @Override
118 public void onVoiceSessionHidden() throws RemoteException {
119 if (VERBOSE) {
120 Log.v(TAG, "Voice closed");
121 }
122 }
123
124 @Override
James O'Leary9c9dd982019-02-08 15:49:06 -0500125 public void onSetUiHints(Bundle hints) {
Matt Casey4cff16f2019-01-14 14:56:06 -0500126 if (VERBOSE) {
James O'Leary9c9dd982019-02-08 15:49:06 -0500127 Log.v(TAG, "UI hints received");
Matt Casey4cff16f2019-01-14 14:56:06 -0500128 }
129 }
130 });
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700131 }
132
Jason Monk9c7844c2017-01-18 15:21:53 -0500133 public void onConfigurationChanged(Configuration newConfiguration) {
134 if (!mInterestingConfigChanges.applyNewConfig(mContext.getResources())) {
135 return;
136 }
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700137 boolean visible = false;
138 if (mView != null) {
139 visible = mView.isShowing();
140 mWindowManager.removeView(mView);
141 }
142
143 mView = (AssistOrbContainer) LayoutInflater.from(mContext).inflate(
144 R.layout.assist_orb, null);
145 mView.setVisibility(View.GONE);
146 mView.setSystemUiVisibility(
147 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
148 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
149 WindowManager.LayoutParams lp = getLayoutParams();
150 mWindowManager.addView(mView, lp);
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700151 if (visible) {
152 mView.show(true /* show */, false /* animate */);
153 }
154 }
155
Annie Chin937a9912016-05-31 10:14:23 -0700156 protected boolean shouldShowOrb() {
157 return true;
158 }
159
Jorim Jaggi165ce062015-07-06 16:18:11 -0700160 public void startAssist(Bundle args) {
Yohei Yukawa528e4682015-09-10 22:21:04 -0700161 final ComponentName assistComponent = getAssistInfo();
162 if (assistComponent == null) {
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700163 return;
164 }
Xiyuan Xiae6de8b92015-06-06 22:18:05 -0700165
Yohei Yukawa528e4682015-09-10 22:21:04 -0700166 final boolean isService = assistComponent.equals(getVoiceInteractorComponentName());
Annie Chin937a9912016-05-31 10:14:23 -0700167 if (!isService || (!isVoiceSessionRunning() && shouldShowOrb())) {
Yohei Yukawa528e4682015-09-10 22:21:04 -0700168 showOrb(assistComponent, isService);
Xiyuan Xiae6de8b92015-06-06 22:18:05 -0700169 mView.postDelayed(mHideRunnable, isService
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700170 ? TIMEOUT_SERVICE
171 : TIMEOUT_ACTIVITY);
172 }
Yohei Yukawa528e4682015-09-10 22:21:04 -0700173 startAssistInternal(args, assistComponent, isService);
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700174 }
175
Jorim Jaggib835dd72015-06-08 12:28:42 -0700176 public void hideAssist() {
Adrian Roose9175082015-06-15 13:23:14 -0700177 mAssistUtils.hideCurrentSession();
Jorim Jaggib835dd72015-06-08 12:28:42 -0700178 }
179
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700180 private WindowManager.LayoutParams getLayoutParams() {
181 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
182 ViewGroup.LayoutParams.MATCH_PARENT,
183 mContext.getResources().getDimensionPixelSize(R.dimen.assist_orb_scrim_height),
184 WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING,
185 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
186 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
187 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
188 PixelFormat.TRANSLUCENT);
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800189 lp.token = new Binder();
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700190 lp.gravity = Gravity.BOTTOM | Gravity.START;
191 lp.setTitle("AssistPreviewPanel");
192 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
193 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
194 return lp;
195 }
196
Yohei Yukawa528e4682015-09-10 22:21:04 -0700197 private void showOrb(@NonNull ComponentName assistComponent, boolean isService) {
198 maybeSwapSearchIcon(assistComponent, isService);
Rajeev Kumar3e084302017-09-25 19:08:12 -0700199 if (mShouldEnableOrb) {
200 mView.show(true /* show */, true /* animate */);
201 }
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700202 }
203
Yohei Yukawa528e4682015-09-10 22:21:04 -0700204 private void startAssistInternal(Bundle args, @NonNull ComponentName assistComponent,
205 boolean isService) {
206 if (isService) {
207 startVoiceInteractor(args);
208 } else {
209 startAssistActivity(args, assistComponent);
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700210 }
211 }
212
Yohei Yukawa528e4682015-09-10 22:21:04 -0700213 private void startAssistActivity(Bundle args, @NonNull ComponentName assistComponent) {
Jason Monk9c7844c2017-01-18 15:21:53 -0500214 if (!mDeviceProvisionedController.isDeviceProvisioned()) {
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700215 return;
216 }
217
218 // Close Recent Apps if needed
Jason Monk9c7844c2017-01-18 15:21:53 -0500219 SysUiServiceProvider.getComponent(mContext, CommandQueue.class).animateCollapsePanels(
Jason Monk297c04e2018-08-23 17:16:59 -0400220 CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL | CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
221 false /* force */);
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700222
Adrian Roos4f43dc02015-06-17 16:43:38 -0700223 boolean structureEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
224 Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
225
Steven Wu2b71d792018-05-08 11:03:17 -0400226 final SearchManager searchManager =
227 (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
228 if (searchManager == null) {
229 return;
230 }
231 final Intent intent = searchManager.getAssistIntent(structureEnabled);
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700232 if (intent == null) {
233 return;
234 }
Yohei Yukawa528e4682015-09-10 22:21:04 -0700235 intent.setComponent(assistComponent);
Jorim Jaggi165ce062015-07-06 16:18:11 -0700236 intent.putExtras(args);
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700237
Adrian Roos4f43dc02015-06-17 16:43:38 -0700238 if (structureEnabled) {
239 showDisclosure();
240 }
241
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700242 try {
243 final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
244 R.anim.search_launch_enter, R.anim.search_launch_exit);
245 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
246 AsyncTask.execute(new Runnable() {
247 @Override
248 public void run() {
249 mContext.startActivityAsUser(intent, opts.toBundle(),
250 new UserHandle(UserHandle.USER_CURRENT));
251 }
252 });
253 } catch (ActivityNotFoundException e) {
254 Log.w(TAG, "Activity not found for " + intent.getAction());
255 }
256 }
257
Jorim Jaggi165ce062015-07-06 16:18:11 -0700258 private void startVoiceInteractor(Bundle args) {
Dianne Hackborn17f69352015-07-17 18:04:14 -0700259 mAssistUtils.showSessionForActiveService(args,
260 VoiceInteractionSession.SHOW_SOURCE_ASSIST_GESTURE, mShowCallback, null);
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700261 }
262
Selim Cineke70d6532015-04-24 16:46:13 -0700263 public void launchVoiceAssistFromKeyguard() {
Adrian Roose9175082015-06-15 13:23:14 -0700264 mAssistUtils.launchVoiceAssistFromKeyguard();
Selim Cineke70d6532015-04-24 16:46:13 -0700265 }
266
Selim Cineke70d6532015-04-24 16:46:13 -0700267 public boolean canVoiceAssistBeLaunchedFromKeyguard() {
Adrian Roose9175082015-06-15 13:23:14 -0700268 return mAssistUtils.activeServiceSupportsLaunchFromKeyguard();
Selim Cineke70d6532015-04-24 16:46:13 -0700269 }
270
271 public ComponentName getVoiceInteractorComponentName() {
Adrian Roose9175082015-06-15 13:23:14 -0700272 return mAssistUtils.getActiveServiceComponentName();
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700273 }
274
275 private boolean isVoiceSessionRunning() {
Adrian Roose9175082015-06-15 13:23:14 -0700276 return mAssistUtils.isSessionRunning();
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700277 }
278
Yohei Yukawa528e4682015-09-10 22:21:04 -0700279 private void maybeSwapSearchIcon(@NonNull ComponentName assistComponent, boolean isService) {
280 replaceDrawable(mView.getOrb().getLogo(), assistComponent, ASSIST_ICON_METADATA_NAME,
281 isService);
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700282 }
283
284 public void replaceDrawable(ImageView v, ComponentName component, String name,
285 boolean isService) {
286 if (component != null) {
287 try {
288 PackageManager packageManager = mContext.getPackageManager();
289 // Look for the search icon specified in the activity meta-data
290 Bundle metaData = isService
291 ? packageManager.getServiceInfo(
292 component, PackageManager.GET_META_DATA).metaData
293 : packageManager.getActivityInfo(
294 component, PackageManager.GET_META_DATA).metaData;
295 if (metaData != null) {
296 int iconResId = metaData.getInt(name);
297 if (iconResId != 0) {
298 Resources res = packageManager.getResourcesForApplication(
299 component.getPackageName());
300 v.setImageDrawable(res.getDrawable(iconResId));
301 return;
302 }
303 }
304 } catch (PackageManager.NameNotFoundException e) {
Matt Casey4cff16f2019-01-14 14:56:06 -0500305 if (VERBOSE) {
306 Log.v(TAG, "Assistant component "
307 + component.flattenToShortString() + " not found");
308 }
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700309 } catch (Resources.NotFoundException nfe) {
310 Log.w(TAG, "Failed to swap drawable from "
311 + component.flattenToShortString(), nfe);
312 }
313 }
314 v.setImageDrawable(null);
315 }
316
Yohei Yukawa528e4682015-09-10 22:21:04 -0700317 @Nullable
318 private ComponentName getAssistInfo() {
Kaori Katou70554e02016-08-04 17:11:07 +0900319 return mAssistUtils.getAssistComponentForUser(KeyguardUpdateMonitor.getCurrentUser());
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700320 }
Adrian Roos4f43dc02015-06-17 16:43:38 -0700321
322 public void showDisclosure() {
323 mAssistDisclosure.postShow();
324 }
Selim Cinek9a634992015-06-23 01:10:07 -0400325
Jorim Jaggi19695d92015-07-20 15:51:40 -0700326 public void onLockscreenShown() {
327 mAssistUtils.onLockscreenShown();
328 }
Jorim Jaggi2fdeeab2015-04-01 15:13:03 -0700329}