OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / packages / SystemUI / src / com / android / systemui / assist / AssistManager.java
1 package com.android.systemui.assist;
2
3 import android.annotation.NonNull;
4 import android.annotation.Nullable;
5 import android.app.ActivityManager;
6 import android.app.ActivityOptions;
7 import android.app.SearchManager;
8 import android.content.ActivityNotFoundException;
9 import android.content.ComponentName;
10 import android.content.Context;
11 import android.content.Intent;
12 import android.content.pm.PackageManager;
13 import android.content.res.Resources;
14 import android.graphics.PixelFormat;
15 import android.os.AsyncTask;
16 import android.os.Bundle;
17 import android.os.Handler;
18 import android.os.IBinder;
19 import android.os.RemoteException;
20 import android.os.UserHandle;
21 import android.provider.Settings;
22 import android.service.voice.VoiceInteractionSession;
23 import android.util.Log;
24 import android.view.Gravity;
25 import android.view.LayoutInflater;
26 import android.view.View;
27 import android.view.ViewGroup;
28 import android.view.WindowManager;
29 import android.widget.ImageView;
30
31 import com.android.internal.app.AssistUtils;
32 import com.android.internal.app.IVoiceInteractionSessionListener;
33 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
34 import com.android.systemui.R;
35 import com.android.systemui.statusbar.BaseStatusBar;
36 import com.android.systemui.statusbar.CommandQueue;
37
38 /**
39  * Class to manage everything related to assist in SystemUI.
40  */
41 public class AssistManager {
42
43     private static final String TAG = "AssistManager";
44     private static final String ASSIST_ICON_METADATA_NAME =
45             "com.android.systemui.action_assist_icon";
46
47     private static final long TIMEOUT_SERVICE = 2500;
48     private static final long TIMEOUT_ACTIVITY = 1000;
49
50     protected final Context mContext;
51     private final WindowManager mWindowManager;
52     private final AssistDisclosure mAssistDisclosure;
53
54     private AssistOrbContainer mView;
55     private final BaseStatusBar mBar;
56     protected final AssistUtils mAssistUtils;
57
58     private IVoiceInteractionSessionShowCallback mShowCallback =
59             new IVoiceInteractionSessionShowCallback.Stub() {
60
61         @Override
62         public void onFailed() throws RemoteException {
63             mView.post(mHideRunnable);
64         }
65
66         @Override
67         public void onShown() throws RemoteException {
68             mView.post(mHideRunnable);
69         }
70     };
71
72     private Runnable mHideRunnable = new Runnable() {
73         @Override
74         public void run() {
75             mView.removeCallbacks(this);
76             mView.show(false /* show */, true /* animate */);
77         }
78     };
79
80     public AssistManager(BaseStatusBar bar, Context context) {
81         mContext = context;
82         mBar = bar;
83         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
84         mAssistUtils = new AssistUtils(context);
85         mAssistDisclosure = new AssistDisclosure(context, new Handler());
86
87         registerVoiceInteractionSessionListener();
88     }
89
90     protected void registerVoiceInteractionSessionListener() {
91         mAssistUtils.registerVoiceInteractionSessionListener(
92                 new IVoiceInteractionSessionListener.Stub() {
93             @Override
94             public void onVoiceSessionShown() throws RemoteException {
95                 Log.v(TAG, "Voice open");
96             }
97
98             @Override
99             public void onVoiceSessionHidden() throws RemoteException {
100                 Log.v(TAG, "Voice closed");
101             }
102         });
103     }
104
105     public void onConfigurationChanged() {
106         boolean visible = false;
107         if (mView != null) {
108             visible = mView.isShowing();
109             mWindowManager.removeView(mView);
110         }
111
112         mView = (AssistOrbContainer) LayoutInflater.from(mContext).inflate(
113                 R.layout.assist_orb, null);
114         mView.setVisibility(View.GONE);
115         mView.setSystemUiVisibility(
116                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
117                         | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
118         WindowManager.LayoutParams lp = getLayoutParams();
119         mWindowManager.addView(mView, lp);
120         if (visible) {
121             mView.show(true /* show */, false /* animate */);
122         }
123     }
124
125     protected boolean shouldShowOrb() {
126         return true;
127     }
128
129     public void startAssist(Bundle args) {
130         final ComponentName assistComponent = getAssistInfo();
131         if (assistComponent == null) {
132             return;
133         }
134
135         final boolean isService = assistComponent.equals(getVoiceInteractorComponentName());
136         if (!isService || (!isVoiceSessionRunning() && shouldShowOrb())) {
137             showOrb(assistComponent, isService);
138             mView.postDelayed(mHideRunnable, isService
139                     ? TIMEOUT_SERVICE
140                     : TIMEOUT_ACTIVITY);
141         }
142         startAssistInternal(args, assistComponent, isService);
143     }
144
145     public void hideAssist() {
146         mAssistUtils.hideCurrentSession();
147     }
148
149     private WindowManager.LayoutParams getLayoutParams() {
150         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
151                 ViewGroup.LayoutParams.MATCH_PARENT,
152                 mContext.getResources().getDimensionPixelSize(R.dimen.assist_orb_scrim_height),
153                 WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING,
154                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
155                         | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
156                         | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
157                 PixelFormat.TRANSLUCENT);
158         if (ActivityManager.isHighEndGfx()) {
159             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
160         }
161         lp.gravity = Gravity.BOTTOM | Gravity.START;
162         lp.setTitle("AssistPreviewPanel");
163         lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
164                 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
165         return lp;
166     }
167
168     private void showOrb(@NonNull ComponentName assistComponent, boolean isService) {
169         maybeSwapSearchIcon(assistComponent, isService);
170         mView.show(true /* show */, true /* animate */);
171     }
172
173     private void startAssistInternal(Bundle args, @NonNull ComponentName assistComponent,
174             boolean isService) {
175         if (isService) {
176             startVoiceInteractor(args);
177         } else {
178             startAssistActivity(args, assistComponent);
179         }
180     }
181
182     private void startAssistActivity(Bundle args, @NonNull ComponentName assistComponent) {
183         if (!mBar.isDeviceProvisioned()) {
184             return;
185         }
186
187         // Close Recent Apps if needed
188         mBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL |
189                 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL);
190
191         boolean structureEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
192                 Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
193
194         final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
195                 .getAssistIntent(structureEnabled);
196         if (intent == null) {
197             return;
198         }
199         intent.setComponent(assistComponent);
200         intent.putExtras(args);
201
202         if (structureEnabled) {
203             showDisclosure();
204         }
205
206         try {
207             final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
208                     R.anim.search_launch_enter, R.anim.search_launch_exit);
209             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
210             AsyncTask.execute(new Runnable() {
211                 @Override
212                 public void run() {
213                     mContext.startActivityAsUser(intent, opts.toBundle(),
214                             new UserHandle(UserHandle.USER_CURRENT));
215                 }
216             });
217         } catch (ActivityNotFoundException e) {
218             Log.w(TAG, "Activity not found for " + intent.getAction());
219         }
220     }
221
222     private void startVoiceInteractor(Bundle args) {
223         mAssistUtils.showSessionForActiveService(args,
224                 VoiceInteractionSession.SHOW_SOURCE_ASSIST_GESTURE, mShowCallback, null);
225     }
226
227     public void launchVoiceAssistFromKeyguard() {
228         mAssistUtils.launchVoiceAssistFromKeyguard();
229     }
230
231     public boolean canVoiceAssistBeLaunchedFromKeyguard() {
232         return mAssistUtils.activeServiceSupportsLaunchFromKeyguard();
233     }
234
235     public ComponentName getVoiceInteractorComponentName() {
236         return mAssistUtils.getActiveServiceComponentName();
237     }
238
239     private boolean isVoiceSessionRunning() {
240         return mAssistUtils.isSessionRunning();
241     }
242
243     public void destroy() {
244         mWindowManager.removeViewImmediate(mView);
245     }
246
247     private void maybeSwapSearchIcon(@NonNull ComponentName assistComponent, boolean isService) {
248         replaceDrawable(mView.getOrb().getLogo(), assistComponent, ASSIST_ICON_METADATA_NAME,
249                 isService);
250     }
251
252     public void replaceDrawable(ImageView v, ComponentName component, String name,
253             boolean isService) {
254         if (component != null) {
255             try {
256                 PackageManager packageManager = mContext.getPackageManager();
257                 // Look for the search icon specified in the activity meta-data
258                 Bundle metaData = isService
259                         ? packageManager.getServiceInfo(
260                                 component, PackageManager.GET_META_DATA).metaData
261                         : packageManager.getActivityInfo(
262                                 component, PackageManager.GET_META_DATA).metaData;
263                 if (metaData != null) {
264                     int iconResId = metaData.getInt(name);
265                     if (iconResId != 0) {
266                         Resources res = packageManager.getResourcesForApplication(
267                                 component.getPackageName());
268                         v.setImageDrawable(res.getDrawable(iconResId));
269                         return;
270                     }
271                 }
272             } catch (PackageManager.NameNotFoundException e) {
273                 Log.v(TAG, "Assistant component "
274                         + component.flattenToShortString() + " not found");
275             } catch (Resources.NotFoundException nfe) {
276                 Log.w(TAG, "Failed to swap drawable from "
277                         + component.flattenToShortString(), nfe);
278             }
279         }
280         v.setImageDrawable(null);
281     }
282
283     @Nullable
284     private ComponentName getAssistInfo() {
285         return mAssistUtils.getAssistComponentForUser(UserHandle.USER_CURRENT);
286     }
287
288     public void showDisclosure() {
289         mAssistDisclosure.postShow();
290     }
291
292     public void onLockscreenShown() {
293         mAssistUtils.onLockscreenShown();
294     }
295 }