am 4f43dc04: Assist disclosure
* commit '4f43dc042bf76ec6c3b340b2297dec7c4cdd9098': Assist disclosure
This commit is contained in:
@@ -64,5 +64,7 @@ oneway interface IStatusBar
|
||||
* bar caused by this app transition in millis
|
||||
*/
|
||||
void appTransitionStarting(long statusBarAnimationsStartTime, long statusBarAnimationsDuration);
|
||||
|
||||
void showAssistDisclosure();
|
||||
}
|
||||
|
||||
|
||||
@@ -578,4 +578,10 @@
|
||||
|
||||
<!-- Padding between icon and text for managed profile toast -->
|
||||
<dimen name="managed_profile_toast_padding">4dp</dimen>
|
||||
|
||||
<!-- Thickness of the assist disclosure beams -->
|
||||
<dimen name="assist_disclosure_thickness">4dp</dimen>
|
||||
|
||||
<!-- Thickness of the shadows of the assist disclosure beams -->
|
||||
<dimen name="assist_disclosure_shadow_thickness">1.5dp</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* 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.systemui.assist;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.animation.AnimationUtils;
|
||||
|
||||
/**
|
||||
* Visually discloses that contextual data was provided to an assistant.
|
||||
*/
|
||||
public class AssistDisclosure {
|
||||
private final Context mContext;
|
||||
private final WindowManager mWm;
|
||||
private final Handler mHandler;
|
||||
|
||||
private AssistDisclosureView mView;
|
||||
private boolean mViewAdded;
|
||||
|
||||
public AssistDisclosure(Context context, Handler handler) {
|
||||
mContext = context;
|
||||
mHandler = handler;
|
||||
mWm = mContext.getSystemService(WindowManager.class);
|
||||
}
|
||||
|
||||
public void postShow() {
|
||||
mHandler.removeCallbacks(mShowRunnable);
|
||||
mHandler.post(mShowRunnable);
|
||||
}
|
||||
|
||||
private void show() {
|
||||
if (mView == null) {
|
||||
mView = new AssistDisclosureView(mContext);
|
||||
}
|
||||
if (!mViewAdded) {
|
||||
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
|
||||
WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
|
||||
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
|
||||
| WindowManager.LayoutParams.FLAG_FULLSCREEN
|
||||
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
lp.setTitle("AssistDisclosure");
|
||||
|
||||
mWm.addView(mView, lp);
|
||||
mViewAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void hide() {
|
||||
if (mViewAdded) {
|
||||
mWm.removeView(mView);
|
||||
mViewAdded = false;
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable mShowRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
show();
|
||||
}
|
||||
};
|
||||
|
||||
private class AssistDisclosureView extends View
|
||||
implements ValueAnimator.AnimatorUpdateListener {
|
||||
|
||||
public static final int TRACING_ANIMATION_DURATION = 300;
|
||||
public static final int ALPHA_ANIMATION_DURATION = 200;
|
||||
|
||||
private float mThickness;
|
||||
private float mShadowThickness;
|
||||
private final Paint mPaint = new Paint();
|
||||
private final Paint mShadowPaint = new Paint();
|
||||
|
||||
private final ValueAnimator mTracingAnimator;
|
||||
private final ValueAnimator mAlphaAnimator;
|
||||
private final AnimatorSet mAnimator;
|
||||
|
||||
private float mTracingProgress = 0;
|
||||
private int mAlpha = 255;
|
||||
|
||||
public AssistDisclosureView(Context context) {
|
||||
super(context);
|
||||
|
||||
mTracingAnimator = ValueAnimator.ofFloat(0, 1).setDuration(TRACING_ANIMATION_DURATION);
|
||||
mTracingAnimator.addUpdateListener(this);
|
||||
mTracingAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext,
|
||||
android.R.interpolator.fast_out_slow_in));
|
||||
mAlphaAnimator = ValueAnimator.ofInt(255, 0).setDuration(ALPHA_ANIMATION_DURATION);
|
||||
mAlphaAnimator.addUpdateListener(this);
|
||||
mAlphaAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext,
|
||||
android.R.interpolator.fast_out_linear_in));
|
||||
mAnimator = new AnimatorSet();
|
||||
mAnimator.play(mTracingAnimator).before(mAlphaAnimator);
|
||||
mAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
boolean mCancelled;
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
mCancelled = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
mCancelled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (!mCancelled) {
|
||||
hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
PorterDuffXfermode srcMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
|
||||
mPaint.setColor(Color.WHITE);
|
||||
mPaint.setXfermode(srcMode);
|
||||
mShadowPaint.setColor(Color.DKGRAY);
|
||||
mShadowPaint.setXfermode(srcMode);
|
||||
|
||||
mThickness = getResources().getDimension(R.dimen.assist_disclosure_thickness);
|
||||
mShadowThickness = getResources().getDimension(
|
||||
R.dimen.assist_disclosure_shadow_thickness);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
|
||||
startAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
|
||||
mAnimator.cancel();
|
||||
|
||||
mTracingProgress = 0;
|
||||
mAlpha = 255;
|
||||
}
|
||||
|
||||
private void startAnimation() {
|
||||
mAnimator.cancel();
|
||||
mAnimator.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
mPaint.setAlpha(mAlpha);
|
||||
mShadowPaint.setAlpha(mAlpha / 4);
|
||||
|
||||
drawGeometry(canvas, mShadowPaint, mShadowThickness);
|
||||
drawGeometry(canvas, mPaint, 0);
|
||||
}
|
||||
|
||||
private void drawGeometry(Canvas canvas, Paint paint, float padding) {
|
||||
final int width = getWidth();
|
||||
final int height = getHeight();
|
||||
float thickness = mThickness;
|
||||
final float pixelProgress = mTracingProgress * (width + height - 2 * thickness);
|
||||
|
||||
float bottomProgress = Math.min(pixelProgress, width / 2f);
|
||||
if (bottomProgress > 0) {
|
||||
drawBeam(canvas,
|
||||
width / 2f - bottomProgress,
|
||||
height - thickness,
|
||||
width / 2f + bottomProgress,
|
||||
height, paint, padding);
|
||||
}
|
||||
|
||||
float sideProgress = Math.min(pixelProgress - bottomProgress, height - thickness);
|
||||
if (sideProgress > 0) {
|
||||
drawBeam(canvas,
|
||||
0,
|
||||
(height - thickness) - sideProgress,
|
||||
thickness,
|
||||
height - thickness, paint, padding);
|
||||
drawBeam(canvas,
|
||||
width - thickness,
|
||||
(height - thickness) - sideProgress,
|
||||
width,
|
||||
height - thickness, paint, padding);
|
||||
}
|
||||
|
||||
float topProgress = Math.min(pixelProgress - bottomProgress - sideProgress,
|
||||
width / 2 - thickness);
|
||||
if (sideProgress > 0 && topProgress > 0) {
|
||||
drawBeam(canvas,
|
||||
thickness,
|
||||
0,
|
||||
thickness + topProgress,
|
||||
thickness, paint, padding);
|
||||
drawBeam(canvas,
|
||||
(width - thickness) - topProgress,
|
||||
0,
|
||||
width - thickness,
|
||||
thickness, paint, padding);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawBeam(Canvas canvas, float left, float top, float right, float bottom,
|
||||
Paint paint, float padding) {
|
||||
canvas.drawRect(left - padding,
|
||||
top - padding,
|
||||
right + padding,
|
||||
bottom + padding,
|
||||
paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
if (animation == mAlphaAnimator) {
|
||||
mAlpha = (int) mAlphaAnimator.getAnimatedValue();
|
||||
} else if (animation == mTracingAnimator) {
|
||||
mTracingProgress = (float) mTracingAnimator.getAnimatedValue();
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,8 @@ public class AssistManager {
|
||||
|
||||
private final Context mContext;
|
||||
private final WindowManager mWindowManager;
|
||||
private final AssistDisclosure mAssistDisclosure;
|
||||
|
||||
private AssistOrbContainer mView;
|
||||
private final PhoneStatusBar mBar;
|
||||
private final AssistUtils mAssistUtils;
|
||||
@@ -100,6 +102,7 @@ public class AssistManager {
|
||||
Settings.Secure.getUriFor(Settings.Secure.ASSISTANT), false,
|
||||
mAssistSettingsObserver);
|
||||
mAssistSettingsObserver.onChange(false);
|
||||
mAssistDisclosure = new AssistDisclosure(context, new Handler());
|
||||
}
|
||||
|
||||
public void onConfigurationChanged() {
|
||||
@@ -187,8 +190,11 @@ public class AssistManager {
|
||||
mBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL |
|
||||
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL);
|
||||
|
||||
boolean structureEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
|
||||
|
||||
final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
|
||||
.getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
|
||||
.getAssistIntent(mContext, structureEnabled, UserHandle.USER_CURRENT);
|
||||
if (intent == null) {
|
||||
return;
|
||||
}
|
||||
@@ -196,6 +202,10 @@ public class AssistManager {
|
||||
intent.setComponent(mAssistComponent);
|
||||
}
|
||||
|
||||
if (structureEnabled) {
|
||||
showDisclosure();
|
||||
}
|
||||
|
||||
try {
|
||||
final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
|
||||
R.anim.search_launch_enter, R.anim.search_launch_exit);
|
||||
@@ -297,4 +307,8 @@ public class AssistManager {
|
||||
pw.println("AssistManager state:");
|
||||
pw.print(" mAssistComponent="); pw.println(mAssistComponent);
|
||||
}
|
||||
|
||||
public void showDisclosure() {
|
||||
mAssistDisclosure.postShow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2101,4 +2101,11 @@ public abstract class BaseStatusBar extends SystemUI implements
|
||||
}
|
||||
return mStatusBarKeyguardViewManager.isSecure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showAssistDisclosure() {
|
||||
if (mAssistManager != null) {
|
||||
mAssistManager.showDisclosure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ public class CommandQueue extends IStatusBar.Stub {
|
||||
private static final int MSG_APP_TRANSITION_PENDING = 19 << MSG_SHIFT;
|
||||
private static final int MSG_APP_TRANSITION_CANCELLED = 20 << MSG_SHIFT;
|
||||
private static final int MSG_APP_TRANSITION_STARTING = 21 << MSG_SHIFT;
|
||||
private static final int MSG_ASSIST_DISCLOSURE = 22 << MSG_SHIFT;
|
||||
|
||||
public static final int FLAG_EXCLUDE_NONE = 0;
|
||||
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
|
||||
@@ -104,6 +105,7 @@ public class CommandQueue extends IStatusBar.Stub {
|
||||
public void appTransitionPending();
|
||||
public void appTransitionCancelled();
|
||||
public void appTransitionStarting(long startTime, long duration);
|
||||
public void showAssistDisclosure();
|
||||
}
|
||||
|
||||
public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
|
||||
@@ -274,6 +276,13 @@ public class CommandQueue extends IStatusBar.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
public void showAssistDisclosure() {
|
||||
synchronized (mList) {
|
||||
mHandler.removeMessages(MSG_ASSIST_DISCLOSURE);
|
||||
mHandler.obtainMessage(MSG_ASSIST_DISCLOSURE).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
private final class H extends Handler {
|
||||
public void handleMessage(Message msg) {
|
||||
final int what = msg.what & MSG_MASK;
|
||||
@@ -366,6 +375,9 @@ public class CommandQueue extends IStatusBar.Stub {
|
||||
Pair<Long, Long> data = (Pair<Long, Long>) msg.obj;
|
||||
mCallbacks.appTransitionStarting(data.first, data.second);
|
||||
break;
|
||||
case MSG_ASSIST_DISCLOSURE:
|
||||
mCallbacks.showAssistDisclosure();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,4 +24,5 @@ public interface StatusBarManagerInternal {
|
||||
void notificationLightPulse(int argb, int onMillis, int offMillis);
|
||||
void notificationLightOff();
|
||||
void showScreenPinningRequest();
|
||||
void showAssistDisclosure();
|
||||
}
|
||||
|
||||
@@ -154,6 +154,16 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showAssistDisclosure() {
|
||||
if (mBar != null) {
|
||||
try {
|
||||
mBar.showAssistDisclosure();
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ================================================================================
|
||||
|
||||
@@ -139,7 +139,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
|
||||
IVoiceInteractionSessionShowCallback showCallback) {
|
||||
if (mActiveSession == null) {
|
||||
mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName,
|
||||
mUser, mContext, this, mInfo.getServiceInfo().applicationInfo.uid);
|
||||
mUser, mContext, this, mInfo.getServiceInfo().applicationInfo.uid, mHandler);
|
||||
}
|
||||
return mActiveSession.showLocked(args, flags, showCallback);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
@@ -48,6 +49,8 @@ import com.android.internal.app.IAssistScreenshotReceiver;
|
||||
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
|
||||
import com.android.internal.app.IVoiceInteractor;
|
||||
import com.android.internal.os.IResultReceiver;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.statusbar.StatusBarManagerInternal;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -63,6 +66,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
|
||||
final Context mContext;
|
||||
final Callback mCallback;
|
||||
final int mCallingUid;
|
||||
final Handler mHandler;
|
||||
final IActivityManager mAm;
|
||||
final IWindowManager mIWindowManager;
|
||||
final AppOpsManager mAppOps;
|
||||
@@ -141,13 +145,14 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
|
||||
};
|
||||
|
||||
public VoiceInteractionSessionConnection(Object lock, ComponentName component, int user,
|
||||
Context context, Callback callback, int callingUid) {
|
||||
Context context, Callback callback, int callingUid, Handler handler) {
|
||||
mLock = lock;
|
||||
mSessionComponentName = component;
|
||||
mUser = user;
|
||||
mContext = context;
|
||||
mCallback = callback;
|
||||
mCallingUid = callingUid;
|
||||
mHandler = handler;
|
||||
mAm = ActivityManagerNative.getDefault();
|
||||
mIWindowManager = IWindowManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.WINDOW_SERVICE));
|
||||
@@ -193,11 +198,13 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
|
||||
mShowArgs = args;
|
||||
mShowFlags = flags;
|
||||
mHaveAssistData = false;
|
||||
boolean needDisclosure = false;
|
||||
if ((flags& VoiceInteractionSession.SHOW_WITH_ASSIST) != 0) {
|
||||
if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid,
|
||||
mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
|
||||
&& allDataEnabled) {
|
||||
try {
|
||||
needDisclosure = true;
|
||||
mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
|
||||
mAssistReceiver);
|
||||
} catch (RemoteException e) {
|
||||
@@ -215,6 +222,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
|
||||
mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
|
||||
&& allDataEnabled) {
|
||||
try {
|
||||
needDisclosure = true;
|
||||
mIWindowManager.requestAssistScreenshot(mScreenshotReceiver);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
@@ -225,6 +233,9 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
|
||||
} else {
|
||||
mScreenshot = null;
|
||||
}
|
||||
if (needDisclosure) {
|
||||
mHandler.post(mShowAssistDisclosureRunnable);
|
||||
}
|
||||
if (mSession != null) {
|
||||
try {
|
||||
mSession.show(mShowArgs, mShowFlags, showCallback);
|
||||
@@ -483,4 +494,15 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
|
||||
pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData);
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable mShowAssistDisclosureRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
StatusBarManagerInternal statusBarInternal = LocalServices.getService(
|
||||
StatusBarManagerInternal.class);
|
||||
if (statusBarInternal != null) {
|
||||
statusBarInternal.showAssistDisclosure();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user