diff options
Diffstat (limited to 'packages/SystemUI/src/com/android/systemui/assist/AssistManager.java')
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/assist/AssistManager.java | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java new file mode 100644 index 0000000..d1f8963 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -0,0 +1,309 @@ +package com.android.systemui.assist; + +import android.app.ActivityManager; +import android.app.ActivityOptions; +import android.app.SearchManager; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.media.AudioAttributes; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.UserHandle; +import android.os.Vibrator; +import android.provider.Settings; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.ImageView; + +import com.android.internal.app.IVoiceInteractionManagerService; +import com.android.internal.app.IVoiceInteractionSessionShowCallback; +import com.android.systemui.R; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.phone.PhoneStatusBar; + +/** + * Class to manage everything related to assist in SystemUI. + */ +public class AssistManager { + + private static final String TAG = "AssistManager"; + private static final String ASSIST_ICON_METADATA_NAME = + "com.android.systemui.action_assist_icon"; + + private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) + .build(); + + private static final long TIMEOUT_SERVICE = 2500; + private static final long TIMEOUT_ACTIVITY = 1000; + + private final Context mContext; + private final WindowManager mWindowManager; + private AssistOrbContainer mView; + private final PhoneStatusBar mBar; + private final IVoiceInteractionManagerService mVoiceInteractionManagerService; + + private IVoiceInteractionSessionShowCallback mShowCallback = + new IVoiceInteractionSessionShowCallback.Stub() { + + @Override + public void onFailed() throws RemoteException { + mView.post(mHideRunnable); + } + + @Override + public void onShown() throws RemoteException { + mView.post(mHideRunnable); + } + }; + + private Runnable mHideRunnable = new Runnable() { + @Override + public void run() { + mView.removeCallbacks(this); + mView.show(false /* show */, true /* animate */); + } + }; + + public AssistManager(PhoneStatusBar bar, Context context) { + mContext = context; + mBar = bar; + mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + mVoiceInteractionManagerService = IVoiceInteractionManagerService.Stub.asInterface( + ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE)); + } + + public void onConfigurationChanged() { + boolean visible = false; + if (mView != null) { + visible = mView.isShowing(); + mWindowManager.removeView(mView); + } + + mView = (AssistOrbContainer) LayoutInflater.from(mContext).inflate( + R.layout.assist_orb, null); + mView.setVisibility(View.GONE); + mView.setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + WindowManager.LayoutParams lp = getLayoutParams(); + mWindowManager.addView(mView, lp); + mBar.getNavigationBarView().setDelegateView(mView); + if (visible) { + mView.show(true /* show */, false /* animate */); + } + } + + public void onGestureInvoked(boolean vibrate) { + boolean isVoiceInteractorActive = getVoiceInteractorSupportsAssistGesture(); + if (!isVoiceInteractorActive && !isAssistantIntentAvailable()) { + return; + } + if (vibrate) { + vibrate(); + } + if (!isVoiceInteractorActive || !isVoiceSessionRunning()) { + showOrb(); + mView.postDelayed(mHideRunnable, isVoiceInteractorActive + ? TIMEOUT_SERVICE + : TIMEOUT_ACTIVITY); + } + startAssist(); + } + + private WindowManager.LayoutParams getLayoutParams() { + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + mContext.getResources().getDimensionPixelSize(R.dimen.assist_orb_scrim_height), + WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING, + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.TRANSLUCENT); + if (ActivityManager.isHighEndGfx()) { + lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; + } + lp.gravity = Gravity.BOTTOM | Gravity.START; + lp.setTitle("AssistPreviewPanel"); + lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED + | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; + return lp; + } + + private void showOrb() { + maybeSwapSearchIcon(); + mView.show(true /* show */, true /* animate */); + } + + private void startAssist() { + if (getVoiceInteractorSupportsAssistGesture()) { + startVoiceInteractor(); + } else { + startAssistActivity(); + } + } + + private void startAssistActivity() { + if (!mBar.isDeviceProvisioned()) { + return; + } + + // Close Recent Apps if needed + mBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL | + CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL); + + final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) + .getAssistIntent(mContext, true, UserHandle.USER_CURRENT); + if (intent == null) { + return; + } + + try { + final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, + R.anim.search_launch_enter, R.anim.search_launch_exit); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + AsyncTask.execute(new Runnable() { + @Override + public void run() { + mContext.startActivityAsUser(intent, opts.toBundle(), + new UserHandle(UserHandle.USER_CURRENT)); + } + }); + } catch (ActivityNotFoundException e) { + Log.w(TAG, "Activity not found for " + intent.getAction()); + } + } + + private void startVoiceInteractor() { + try { + mVoiceInteractionManagerService.showSessionForActiveService(mShowCallback); + } catch (RemoteException e) { + Log.w(TAG, "Failed to call showSessionForActiveService", e); + } + } + + public void launchVoiceAssistFromKeyguard() { + try { + mVoiceInteractionManagerService.launchVoiceAssistFromKeyguard(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to call launchVoiceAssistFromKeyguard", e); + } + } + + private boolean getVoiceInteractorSupportsAssistGesture() { + try { + return mVoiceInteractionManagerService.activeServiceSupportsAssist(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to call activeServiceSupportsAssistGesture", e); + return false; + } + } + + public boolean canVoiceAssistBeLaunchedFromKeyguard() { + try { + return mVoiceInteractionManagerService.activeServiceSupportsLaunchFromKeyguard(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to call activeServiceSupportsLaunchFromKeyguard", e); + return false; + } + } + + public ComponentName getVoiceInteractorComponentName() { + try { + return mVoiceInteractionManagerService.getActiveServiceComponentName(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to call getActiveServiceComponentName", e); + return null; + } + } + + private boolean isVoiceSessionRunning() { + try { + return mVoiceInteractionManagerService.isSessionRunning(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to call isSessionRunning", e); + return false; + } + } + + public void destroy() { + mWindowManager.removeViewImmediate(mView); + } + + private void maybeSwapSearchIcon() { + Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) + .getAssistIntent(mContext, false, UserHandle.USER_CURRENT); + ComponentName component = null; + boolean isService = false; + if (getVoiceInteractorSupportsAssistGesture()) { + component = getVoiceInteractorComponentName(); + isService = true; + } else if (intent != null) { + component = intent.getComponent(); + } + if (component != null) { + replaceDrawable(mView.getOrb().getLogo(), component, ASSIST_ICON_METADATA_NAME, + isService); + } else { + mView.getOrb().getLogo().setImageDrawable(null); + } + } + + public void replaceDrawable(ImageView v, ComponentName component, String name, + boolean isService) { + if (component != null) { + try { + PackageManager packageManager = mContext.getPackageManager(); + // Look for the search icon specified in the activity meta-data + Bundle metaData = isService + ? packageManager.getServiceInfo( + component, PackageManager.GET_META_DATA).metaData + : packageManager.getActivityInfo( + component, PackageManager.GET_META_DATA).metaData; + if (metaData != null) { + int iconResId = metaData.getInt(name); + if (iconResId != 0) { + Resources res = packageManager.getResourcesForApplication( + component.getPackageName()); + v.setImageDrawable(res.getDrawable(iconResId)); + return; + } + } + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Failed to swap drawable; " + + component.flattenToShortString() + " not found", e); + } catch (Resources.NotFoundException nfe) { + Log.w(TAG, "Failed to swap drawable from " + + component.flattenToShortString(), nfe); + } + } + v.setImageDrawable(null); + } + + private void vibrate() { + if (Settings.System.getIntForUser(mContext.getContentResolver(), + Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0) { + Resources res = mContext.getResources(); + Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); + vibrator.vibrate(res.getInteger(R.integer.config_search_panel_view_vibration_duration), + VIBRATION_ATTRIBUTES); + } + } + + public boolean isAssistantIntentAvailable() { + return ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) + .getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null; + } +} |