Loading packages/SystemUI/res/layout/invocation_lights.xml 0 → 100644 +23 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2019 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 --> <com.android.systemui.assist.ui.InvocationLightsView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:visibility="gone"/> packages/SystemUI/res/values/colors.xml +6 −3 Original line number Diff line number Diff line Loading @@ -174,6 +174,9 @@ <!-- Logout button --> <color name="logout_button_bg_color">#ccffffff</color> <!-- Color for the Assistant invocation lights --> <color name="default_invocation_lights_color">#ffffffff</color> <!-- white --> <!-- GM2 colors --> <color name="GM2_grey_50">#F8F9FA</color> <color name="GM2_grey_100">#F1F3F4</color> Loading packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +73 −16 Original line number Diff line number Diff line Loading @@ -40,8 +40,11 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.settingslib.applications.InterestingConfigChanges; import com.android.systemui.ConfigurationChangedReceiver; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.assist.ui.DefaultUiController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.policy.DeviceProvisionedController; Loading @@ -50,6 +53,40 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController; */ public class AssistManager implements ConfigurationChangedReceiver { /** * Controls the UI for showing Assistant invocation progress. */ public interface UiController { /** * Updates the invocation progress. * * @param type one of INVOCATION_TYPE_GESTURE, INVOCATION_TYPE_ACTIVE_EDGE, * INVOCATION_TYPE_VOICE, INVOCATION_TYPE_QUICK_SEARCH_BAR, * INVOCATION_HOME_BUTTON_LONG_PRESS * @param progress a float between 0 and 1 inclusive. 0 represents the beginning of the * gesture; 1 represents the end. */ void onInvocationProgress(int type, float progress); /** * Called when an invocation gesture completes. * * @param velocity the speed of the invocation gesture, in pixels per millisecond. For * drags, this is 0. */ void onGestureCompletion(float velocity); /** * Called with the Bundle from VoiceInteractionSessionListener.onSetUiHints. */ void processBundle(Bundle hints); /** * Hides the UI. */ void hide(); } private static final String TAG = "AssistManager"; // Note that VERBOSE logging may leak PII (e.g. transcription contents). Loading @@ -76,6 +113,7 @@ public class AssistManager implements ConfigurationChangedReceiver { private final InterestingConfigChanges mInterestingConfigChanges; private final PhoneStateMonitor mPhoneStateMonitor; private final AssistHandleBehaviorController mHandleController; private final UiController mUiController; private AssistOrbContainer mView; private final DeviceProvisionedController mDeviceProvisionedController; Loading Loading @@ -119,6 +157,23 @@ public class AssistManager implements ConfigurationChangedReceiver { | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS); onConfigurationChanged(context.getResources().getConfiguration()); mShouldEnableOrb = !ActivityManager.isLowRamDeviceStatic(); mUiController = new DefaultUiController(mContext); OverviewProxyService overviewProxy = Dependency.get(OverviewProxyService.class); overviewProxy.addCallback(new OverviewProxyService.OverviewProxyListener() { @Override public void onAssistantProgress(float progress) { // Progress goes from 0 to 1 to indicate how close the assist gesture is to // completion. onInvocationProgress(INVOCATION_TYPE_GESTURE, progress); } @Override public void onAssistantGestureCompletion(float velocity) { onGestureCompletion(velocity); } }); } protected void registerVoiceInteractionSessionListener() { Loading Loading @@ -196,21 +251,23 @@ public class AssistManager implements ConfigurationChangedReceiver { // Logs assistant start with invocation type. MetricsLogger.action( new LogMaker(MetricsEvent.ASSISTANT) .setType(MetricsEvent.TYPE_OPEN).setSubtype(args.getInt(INVOCATION_TYPE_KEY))); .setType(MetricsEvent.TYPE_OPEN).setSubtype( args.getInt(INVOCATION_TYPE_KEY))); startAssistInternal(args, assistComponent, isService); } /** Called when the user is performing an assistant invocation action (e.g. Active Edge) */ public void onInvocationProgress(int type, float progress) { // intentional no-op, vendor's AssistManager implementation should override if needed. mUiController.onInvocationProgress(type, progress); } /** Called when the user has invoked the assistant with the incoming velocity, in pixels per /** * Called when the user has invoked the assistant with the incoming velocity, in pixels per * millisecond. For invocations without a velocity (e.g. slow drag), the velocity is set to * zero. */ public void onAssistantGestureCompletion(float velocity) { // intentional no-op, vendor's AssistManager implementation should override if needed. public void onGestureCompletion(float velocity) { mUiController.onGestureCompletion(velocity); } public void hideAssist() { Loading packages/SystemUI/src/com/android/systemui/assist/ui/CircularCornerPathRenderer.java 0 → 100644 +65 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.ui; import android.graphics.Path; /** * Describes paths for circular rounded device corners. */ public final class CircularCornerPathRenderer extends CornerPathRenderer { private final int mCornerRadiusBottom; private final int mCornerRadiusTop; private final int mHeight; private final int mWidth; private final Path mPath = new Path(); public CircularCornerPathRenderer(int cornerRadiusBottom, int cornerRadiusTop, int width, int height) { mCornerRadiusBottom = cornerRadiusBottom; mCornerRadiusTop = cornerRadiusTop; mHeight = height; mWidth = width; } @Override // CornerPathRenderer public Path getCornerPath(Corner corner) { mPath.reset(); switch (corner) { case BOTTOM_LEFT: mPath.moveTo(0, mHeight - mCornerRadiusBottom); mPath.arcTo(0, mHeight - mCornerRadiusBottom * 2, mCornerRadiusBottom * 2, mHeight, 180, -90, true); break; case BOTTOM_RIGHT: mPath.moveTo(mWidth - mCornerRadiusBottom, mHeight); mPath.arcTo(mWidth - mCornerRadiusBottom * 2, mHeight - mCornerRadiusBottom * 2, mWidth, mHeight, 90, -90, true); break; case TOP_RIGHT: mPath.moveTo(mWidth, mCornerRadiusTop); mPath.arcTo(mWidth - mCornerRadiusTop, 0, mWidth, mCornerRadiusTop, 0, -90, true); break; case TOP_LEFT: mPath.moveTo(mCornerRadiusTop, 0); mPath.arcTo(0, 0, mCornerRadiusTop, mCornerRadiusTop, 270, -90, true); break; } return mPath; } } packages/SystemUI/src/com/android/systemui/assist/ui/CornerPathRenderer.java 0 → 100644 +140 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.ui; import android.graphics.Path; import android.graphics.PointF; import java.util.ArrayList; import java.util.List; /** * Handles paths along device corners. */ public abstract class CornerPathRenderer { // The maximum delta between the corner curve and points approximating the corner curve. private static final float ACCEPTABLE_ERROR = 0.1f; /** * For convenience, labels the four device corners. * * Corners must be listed in CCW order, otherwise we'll break rotation. */ public enum Corner { BOTTOM_LEFT, BOTTOM_RIGHT, TOP_RIGHT, TOP_LEFT } /** * Returns the path along the inside of a corner (centered insetAmountPx from the corner's * edge). */ public Path getInsetPath(Corner corner, float insetAmountPx) { return approximateInnerPath(getCornerPath(corner), -insetAmountPx); } /** * Returns the path of a corner (centered on the exact corner). Must be implemented by extending * classes, based on the device-specific rounded corners. A default implementation for circular * corners is provided by CircularCornerPathRenderer. */ public abstract Path getCornerPath(Corner corner); private Path approximateInnerPath(Path input, float delta) { List<PointF> points = shiftBy(getApproximatePoints(input), delta); return toPath(points); } private ArrayList<PointF> getApproximatePoints(Path path) { float[] rawInput = path.approximate(ACCEPTABLE_ERROR); ArrayList<PointF> output = new ArrayList<>(); for (int i = 0; i < rawInput.length; i = i + 3) { output.add(new PointF(rawInput[i + 1], rawInput[i + 2])); } return output; } private ArrayList<PointF> shiftBy(ArrayList<PointF> input, float delta) { ArrayList<PointF> output = new ArrayList<>(); for (int i = 0; i < input.size(); i++) { PointF point = input.get(i); PointF normal = normalAt(input, i); PointF shifted = new PointF(point.x + (normal.x * delta), point.y + (normal.y * delta)); output.add(shifted); } return output; } private Path toPath(List<PointF> points) { Path path = new Path(); if (points.size() > 0) { path.moveTo(points.get(0).x, points.get(0).y); for (PointF point : points.subList(1, points.size())) { path.lineTo(point.x, point.y); } } return path; } private PointF normalAt(List<PointF> points, int index) { PointF d1; if (index == 0) { d1 = new PointF(0, 0); } else { PointF point = points.get(index); PointF previousPoint = points.get(index - 1); d1 = new PointF((point.x - previousPoint.x), (point.y - previousPoint.y)); } PointF d2; if (index == (points.size() - 1)) { d2 = new PointF(0, 0); } else { PointF point = points.get(index); PointF nextPoint = points.get(index + 1); d2 = new PointF((nextPoint.x - point.x), (nextPoint.y - point.y)); } return rotate90Ccw(normalize(new PointF(d1.x + d2.x, d1.y + d2.y))); } private PointF rotate90Ccw(PointF input) { return new PointF(-input.y, input.x); } private float magnitude(PointF point) { return (float) Math.sqrt((point.x * point.x) + (point.y * point.y)); } private PointF normalize(PointF point) { float magnitude = magnitude(point); if (magnitude == 0.f) { return point; } float normal = 1 / magnitude; return new PointF((point.x * normal), (point.y * normal)); } } Loading
packages/SystemUI/res/layout/invocation_lights.xml 0 → 100644 +23 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2019 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 --> <com.android.systemui.assist.ui.InvocationLightsView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:visibility="gone"/>
packages/SystemUI/res/values/colors.xml +6 −3 Original line number Diff line number Diff line Loading @@ -174,6 +174,9 @@ <!-- Logout button --> <color name="logout_button_bg_color">#ccffffff</color> <!-- Color for the Assistant invocation lights --> <color name="default_invocation_lights_color">#ffffffff</color> <!-- white --> <!-- GM2 colors --> <color name="GM2_grey_50">#F8F9FA</color> <color name="GM2_grey_100">#F1F3F4</color> Loading
packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +73 −16 Original line number Diff line number Diff line Loading @@ -40,8 +40,11 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.settingslib.applications.InterestingConfigChanges; import com.android.systemui.ConfigurationChangedReceiver; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.assist.ui.DefaultUiController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.policy.DeviceProvisionedController; Loading @@ -50,6 +53,40 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController; */ public class AssistManager implements ConfigurationChangedReceiver { /** * Controls the UI for showing Assistant invocation progress. */ public interface UiController { /** * Updates the invocation progress. * * @param type one of INVOCATION_TYPE_GESTURE, INVOCATION_TYPE_ACTIVE_EDGE, * INVOCATION_TYPE_VOICE, INVOCATION_TYPE_QUICK_SEARCH_BAR, * INVOCATION_HOME_BUTTON_LONG_PRESS * @param progress a float between 0 and 1 inclusive. 0 represents the beginning of the * gesture; 1 represents the end. */ void onInvocationProgress(int type, float progress); /** * Called when an invocation gesture completes. * * @param velocity the speed of the invocation gesture, in pixels per millisecond. For * drags, this is 0. */ void onGestureCompletion(float velocity); /** * Called with the Bundle from VoiceInteractionSessionListener.onSetUiHints. */ void processBundle(Bundle hints); /** * Hides the UI. */ void hide(); } private static final String TAG = "AssistManager"; // Note that VERBOSE logging may leak PII (e.g. transcription contents). Loading @@ -76,6 +113,7 @@ public class AssistManager implements ConfigurationChangedReceiver { private final InterestingConfigChanges mInterestingConfigChanges; private final PhoneStateMonitor mPhoneStateMonitor; private final AssistHandleBehaviorController mHandleController; private final UiController mUiController; private AssistOrbContainer mView; private final DeviceProvisionedController mDeviceProvisionedController; Loading Loading @@ -119,6 +157,23 @@ public class AssistManager implements ConfigurationChangedReceiver { | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS); onConfigurationChanged(context.getResources().getConfiguration()); mShouldEnableOrb = !ActivityManager.isLowRamDeviceStatic(); mUiController = new DefaultUiController(mContext); OverviewProxyService overviewProxy = Dependency.get(OverviewProxyService.class); overviewProxy.addCallback(new OverviewProxyService.OverviewProxyListener() { @Override public void onAssistantProgress(float progress) { // Progress goes from 0 to 1 to indicate how close the assist gesture is to // completion. onInvocationProgress(INVOCATION_TYPE_GESTURE, progress); } @Override public void onAssistantGestureCompletion(float velocity) { onGestureCompletion(velocity); } }); } protected void registerVoiceInteractionSessionListener() { Loading Loading @@ -196,21 +251,23 @@ public class AssistManager implements ConfigurationChangedReceiver { // Logs assistant start with invocation type. MetricsLogger.action( new LogMaker(MetricsEvent.ASSISTANT) .setType(MetricsEvent.TYPE_OPEN).setSubtype(args.getInt(INVOCATION_TYPE_KEY))); .setType(MetricsEvent.TYPE_OPEN).setSubtype( args.getInt(INVOCATION_TYPE_KEY))); startAssistInternal(args, assistComponent, isService); } /** Called when the user is performing an assistant invocation action (e.g. Active Edge) */ public void onInvocationProgress(int type, float progress) { // intentional no-op, vendor's AssistManager implementation should override if needed. mUiController.onInvocationProgress(type, progress); } /** Called when the user has invoked the assistant with the incoming velocity, in pixels per /** * Called when the user has invoked the assistant with the incoming velocity, in pixels per * millisecond. For invocations without a velocity (e.g. slow drag), the velocity is set to * zero. */ public void onAssistantGestureCompletion(float velocity) { // intentional no-op, vendor's AssistManager implementation should override if needed. public void onGestureCompletion(float velocity) { mUiController.onGestureCompletion(velocity); } public void hideAssist() { Loading
packages/SystemUI/src/com/android/systemui/assist/ui/CircularCornerPathRenderer.java 0 → 100644 +65 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.ui; import android.graphics.Path; /** * Describes paths for circular rounded device corners. */ public final class CircularCornerPathRenderer extends CornerPathRenderer { private final int mCornerRadiusBottom; private final int mCornerRadiusTop; private final int mHeight; private final int mWidth; private final Path mPath = new Path(); public CircularCornerPathRenderer(int cornerRadiusBottom, int cornerRadiusTop, int width, int height) { mCornerRadiusBottom = cornerRadiusBottom; mCornerRadiusTop = cornerRadiusTop; mHeight = height; mWidth = width; } @Override // CornerPathRenderer public Path getCornerPath(Corner corner) { mPath.reset(); switch (corner) { case BOTTOM_LEFT: mPath.moveTo(0, mHeight - mCornerRadiusBottom); mPath.arcTo(0, mHeight - mCornerRadiusBottom * 2, mCornerRadiusBottom * 2, mHeight, 180, -90, true); break; case BOTTOM_RIGHT: mPath.moveTo(mWidth - mCornerRadiusBottom, mHeight); mPath.arcTo(mWidth - mCornerRadiusBottom * 2, mHeight - mCornerRadiusBottom * 2, mWidth, mHeight, 90, -90, true); break; case TOP_RIGHT: mPath.moveTo(mWidth, mCornerRadiusTop); mPath.arcTo(mWidth - mCornerRadiusTop, 0, mWidth, mCornerRadiusTop, 0, -90, true); break; case TOP_LEFT: mPath.moveTo(mCornerRadiusTop, 0); mPath.arcTo(0, 0, mCornerRadiusTop, mCornerRadiusTop, 270, -90, true); break; } return mPath; } }
packages/SystemUI/src/com/android/systemui/assist/ui/CornerPathRenderer.java 0 → 100644 +140 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.ui; import android.graphics.Path; import android.graphics.PointF; import java.util.ArrayList; import java.util.List; /** * Handles paths along device corners. */ public abstract class CornerPathRenderer { // The maximum delta between the corner curve and points approximating the corner curve. private static final float ACCEPTABLE_ERROR = 0.1f; /** * For convenience, labels the four device corners. * * Corners must be listed in CCW order, otherwise we'll break rotation. */ public enum Corner { BOTTOM_LEFT, BOTTOM_RIGHT, TOP_RIGHT, TOP_LEFT } /** * Returns the path along the inside of a corner (centered insetAmountPx from the corner's * edge). */ public Path getInsetPath(Corner corner, float insetAmountPx) { return approximateInnerPath(getCornerPath(corner), -insetAmountPx); } /** * Returns the path of a corner (centered on the exact corner). Must be implemented by extending * classes, based on the device-specific rounded corners. A default implementation for circular * corners is provided by CircularCornerPathRenderer. */ public abstract Path getCornerPath(Corner corner); private Path approximateInnerPath(Path input, float delta) { List<PointF> points = shiftBy(getApproximatePoints(input), delta); return toPath(points); } private ArrayList<PointF> getApproximatePoints(Path path) { float[] rawInput = path.approximate(ACCEPTABLE_ERROR); ArrayList<PointF> output = new ArrayList<>(); for (int i = 0; i < rawInput.length; i = i + 3) { output.add(new PointF(rawInput[i + 1], rawInput[i + 2])); } return output; } private ArrayList<PointF> shiftBy(ArrayList<PointF> input, float delta) { ArrayList<PointF> output = new ArrayList<>(); for (int i = 0; i < input.size(); i++) { PointF point = input.get(i); PointF normal = normalAt(input, i); PointF shifted = new PointF(point.x + (normal.x * delta), point.y + (normal.y * delta)); output.add(shifted); } return output; } private Path toPath(List<PointF> points) { Path path = new Path(); if (points.size() > 0) { path.moveTo(points.get(0).x, points.get(0).y); for (PointF point : points.subList(1, points.size())) { path.lineTo(point.x, point.y); } } return path; } private PointF normalAt(List<PointF> points, int index) { PointF d1; if (index == 0) { d1 = new PointF(0, 0); } else { PointF point = points.get(index); PointF previousPoint = points.get(index - 1); d1 = new PointF((point.x - previousPoint.x), (point.y - previousPoint.y)); } PointF d2; if (index == (points.size() - 1)) { d2 = new PointF(0, 0); } else { PointF point = points.get(index); PointF nextPoint = points.get(index + 1); d2 = new PointF((nextPoint.x - point.x), (nextPoint.y - point.y)); } return rotate90Ccw(normalize(new PointF(d1.x + d2.x, d1.y + d2.y))); } private PointF rotate90Ccw(PointF input) { return new PointF(-input.y, input.x); } private float magnitude(PointF point) { return (float) Math.sqrt((point.x * point.x) + (point.y * point.y)); } private PointF normalize(PointF point) { float magnitude = magnitude(point); if (magnitude == 0.f) { return point; } float normal = 1 / magnitude; return new PointF((point.x * normal), (point.y * normal)); } }