From 8f9f513c19b220401e2ae70cad5c56578d459325 Mon Sep 17 00:00:00 2001 From: Matt Casey Date: Mon, 15 Mar 2021 09:39:45 -0400 Subject: [PATCH] Remove AssistPreviewPanel when orb is not visible. Extract orb logic into a separate controller. Change-Id: Ibf820c894b1eca9935b1dc37fdd91a2486b54c6c --- .../systemui/assist/AssistManager.java | 139 +------------- .../systemui/assist/AssistOrbContainer.java | 18 +- .../systemui/assist/AssistOrbController.java | 180 ++++++++++++++++++ 3 files changed, 201 insertions(+), 136 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index d3168c8d2a05c..a7c1451a1d1b9 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -14,14 +14,8 @@ import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.PixelFormat; import android.metrics.LogMaker; import android.os.AsyncTask; -import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; @@ -30,12 +24,6 @@ import android.os.UserHandle; import android.provider.Settings; import android.service.voice.VoiceInteractionSession; 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.AssistUtils; import com.android.internal.app.IVoiceInteractionSessionListener; @@ -43,7 +31,6 @@ import com.android.internal.app.IVoiceInteractionSessionShowCallback; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.settingslib.applications.InterestingConfigChanges; import com.android.systemui.R; import com.android.systemui.assist.ui.DefaultUiController; import com.android.systemui.dagger.SysUISingleton; @@ -97,8 +84,6 @@ public class AssistManager { // Note that VERBOSE logging may leak PII (e.g. transcription contents). private static final boolean VERBOSE = false; - private static final String ASSIST_ICON_METADATA_NAME = - "com.android.systemui.action_assist_icon"; private static final String INVOCATION_TIME_MS_KEY = "invocation_time_ms"; private static final String INVOCATION_PHONE_STATE_KEY = "invocation_phone_state"; public static final String INVOCATION_TYPE_KEY = "invocation_type"; @@ -123,69 +108,29 @@ public class AssistManager { private static final long TIMEOUT_ACTIVITY = 1000; protected final Context mContext; - private final WindowManager mWindowManager; private final AssistDisclosure mAssistDisclosure; - private final InterestingConfigChanges mInterestingConfigChanges; private final PhoneStateMonitor mPhoneStateMonitor; private final AssistHandleBehaviorController mHandleController; private final UiController mUiController; protected final Lazy mSysUiState; protected final AssistLogger mAssistLogger; - private AssistOrbContainer mView; private final DeviceProvisionedController mDeviceProvisionedController; private final CommandQueue mCommandQueue; + private final AssistOrbController mOrbController; protected final AssistUtils mAssistUtils; - private final boolean mShouldEnableOrb; private IVoiceInteractionSessionShowCallback mShowCallback = new IVoiceInteractionSessionShowCallback.Stub() { @Override public void onFailed() throws RemoteException { - mView.post(mHideRunnable); + mOrbController.postHide(); } @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 */); - } - }; - - private ConfigurationController.ConfigurationListener mConfigurationListener = - new ConfigurationController.ConfigurationListener() { - @Override - public void onConfigChanged(Configuration newConfig) { - if (!mInterestingConfigChanges.applyNewConfig(mContext.getResources())) { - return; - } - boolean visible = false; - if (mView != null) { - visible = mView.isShowing(); - if (mView.isAttachedToWindow()) { - 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); - if (visible) { - mView.show(true /* show */, false /* animate */); - } + mOrbController.postHide(); } }; @@ -205,21 +150,15 @@ public class AssistManager { mContext = context; mDeviceProvisionedController = controller; mCommandQueue = commandQueue; - mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); mAssistUtils = assistUtils; mAssistDisclosure = new AssistDisclosure(context, new Handler()); mPhoneStateMonitor = phoneStateMonitor; mHandleController = handleController; mAssistLogger = assistLogger; - configurationController.addCallback(mConfigurationListener); + mOrbController = new AssistOrbController(configurationController, context); registerVoiceInteractionSessionListener(); - mInterestingConfigChanges = new InterestingConfigChanges(ActivityInfo.CONFIG_ORIENTATION - | ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_UI_MODE - | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS); - mConfigurationListener.onConfigChanged(context.getResources().getConfiguration()); - mShouldEnableOrb = !ActivityManager.isLowRamDeviceStatic(); mUiController = defaultUiController; @@ -282,7 +221,7 @@ public class AssistManager { } protected boolean shouldShowOrb() { - return false; + return !ActivityManager.isLowRamDeviceStatic(); } public void startAssist(Bundle args) { @@ -293,10 +232,8 @@ public class AssistManager { final boolean isService = assistComponent.equals(getVoiceInteractorComponentName()); if (!isService || (!isVoiceSessionRunning() && shouldShowOrb())) { - showOrb(assistComponent, isService); - mView.postDelayed(mHideRunnable, isService - ? TIMEOUT_SERVICE - : TIMEOUT_ACTIVITY); + mOrbController.showOrb(assistComponent, isService); + mOrbController.postHideDelayed(isService ? TIMEOUT_SERVICE : TIMEOUT_ACTIVITY); } if (args == null) { @@ -340,30 +277,6 @@ public class AssistManager { mAssistUtils.hideCurrentSession(); } - 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); - lp.token = new Binder(); - 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(@NonNull ComponentName assistComponent, boolean isService) { - maybeSwapSearchIcon(assistComponent, isService); - if (mShouldEnableOrb) { - mView.show(true /* show */, true /* animate */); - } - } - private void startAssistInternal(Bundle args, @NonNull ComponentName assistComponent, boolean isService) { if (isService) { @@ -440,44 +353,6 @@ public class AssistManager { return mAssistUtils.isSessionRunning(); } - private void maybeSwapSearchIcon(@NonNull ComponentName assistComponent, boolean isService) { - replaceDrawable(mView.getOrb().getLogo(), assistComponent, ASSIST_ICON_METADATA_NAME, - isService); - } - - 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) { - if (VERBOSE) { - Log.v(TAG, "Assistant component " - + component.flattenToShortString() + " not found"); - } - } catch (Resources.NotFoundException nfe) { - Log.w(TAG, "Failed to swap drawable from " - + component.flattenToShortString(), nfe); - } - } - v.setImageDrawable(null); - } - protected AssistHandleBehaviorController getHandleBehaviorController() { return mHandleController; } diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java index f78436a8c51ab..fe48c26c413cf 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java @@ -55,14 +55,17 @@ public class AssistOrbContainer extends FrameLayout { mOrb = (AssistOrbView) findViewById(R.id.assist_orb); } - public void show(final boolean show, boolean animate) { + public void show(final boolean show, boolean animate, Runnable onDone) { if (show) { if (getVisibility() != View.VISIBLE) { setVisibility(View.VISIBLE); if (animate) { - startEnterAnimation(); + startEnterAnimation(onDone); } else { reset(); + if (onDone != null) { + onDone.run(); + } } } } else { @@ -72,10 +75,16 @@ public class AssistOrbContainer extends FrameLayout { public void run() { mAnimatingOut = false; setVisibility(View.GONE); + if (onDone != null) { + onDone.run(); + } } }); } else { setVisibility(View.GONE); + if (onDone != null) { + onDone.run(); + } } } } @@ -87,7 +96,7 @@ public class AssistOrbContainer extends FrameLayout { mNavbarScrim.setAlpha(1f); } - private void startEnterAnimation() { + private void startEnterAnimation(Runnable onDone) { if (mAnimatingOut) { return; } @@ -106,7 +115,8 @@ public class AssistOrbContainer extends FrameLayout { .alpha(1f) .setDuration(300) .setStartDelay(0) - .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN); + .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN) + .withEndAction(onDone); } }); } diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java new file mode 100644 index 0000000000000..81a13a236685a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2021 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.systemui.assist; + +import android.annotation.NonNull; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.os.Binder; +import android.os.Bundle; +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.settingslib.applications.InterestingConfigChanges; +import com.android.systemui.R; +import com.android.systemui.statusbar.policy.ConfigurationController; + +/** + * AssistOrbController controls the showing and hiding of the assistant orb. + */ +public class AssistOrbController { + private static final String ASSIST_ICON_METADATA_NAME = + "com.android.systemui.action_assist_icon"; + private static final String TAG = "AssistOrbController"; + private static final boolean VERBOSE = false; + + private final InterestingConfigChanges mInterestingConfigChanges; + private AssistOrbContainer mView; + private final Context mContext; + private final WindowManager mWindowManager; + + private Runnable mHideRunnable = new Runnable() { + @Override + public void run() { + mView.removeCallbacks(this); + mView.show(false /* show */, true /* animate */, () -> { + mWindowManager.removeView(mView); + }); + } + }; + + private ConfigurationController.ConfigurationListener mConfigurationListener = + new ConfigurationController.ConfigurationListener() { + @Override + public void onConfigChanged(Configuration newConfig) { + if (!mInterestingConfigChanges.applyNewConfig(mContext.getResources())) { + return; + } + boolean visible = false; + if (mView != null) { + visible = mView.isShowing(); + if (mView.isAttachedToWindow()) { + mWindowManager.removeView(mView); + } + } + + if (visible) { + showOrb(false); + } + } + }; + + AssistOrbController(ConfigurationController configurationController, Context context) { + mContext = context; + mWindowManager = mContext.getSystemService(WindowManager.class); + mInterestingConfigChanges = new InterestingConfigChanges(ActivityInfo.CONFIG_ORIENTATION + | ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_UI_MODE + | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS); + + configurationController.addCallback(mConfigurationListener); + mConfigurationListener.onConfigChanged(context.getResources().getConfiguration()); + } + + public void postHide() { + mView.post(mHideRunnable); + } + + public void postHideDelayed(long delayMs) { + mView.postDelayed(mHideRunnable, delayMs); + } + + private void showOrb(boolean animated) { + if (mView == null) { + 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); + } + if (!mView.isAttachedToWindow()) { + WindowManager.LayoutParams params = getLayoutParams(); + mWindowManager.addView(mView, params); + } + mView.show(true, animated, null); + } + + 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); + lp.token = new Binder(); + 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; + } + + public void showOrb(@NonNull ComponentName assistComponent, boolean isService) { + showOrb(true); + maybeSwapSearchIcon(assistComponent, isService); + } + + private void maybeSwapSearchIcon(@NonNull ComponentName assistComponent, boolean isService) { + replaceDrawable(mView.getOrb().getLogo(), assistComponent, ASSIST_ICON_METADATA_NAME, + isService); + } + + 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) { + if (VERBOSE) { + Log.v(TAG, "Assistant component " + + component.flattenToShortString() + " not found"); + } + } catch (Resources.NotFoundException nfe) { + Log.w(TAG, "Failed to swap drawable from " + + component.flattenToShortString(), nfe); + } + } + v.setImageDrawable(null); + } +}