Merge "Show a persistent toast when selecting desktop apps on home screen" into udc-qpr-dev am: 7377639653

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/23298604

Change-Id: Id97cf7fe0e82ebddb11f2cdb1069580266d9cd98
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Ats Jenk
2023-05-18 23:18:10 +00:00
committed by Automerger Merge Worker
7 changed files with 250 additions and 8 deletions

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2023 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.
-->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/rounded_button_radius" />
<solid android:color="?androidprv:attr/materialColorPrimaryContainer" />
</shape>

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2023 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.quickstep.views.DesktopAppSelectView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="wrap_content"
android:layout_height="@dimen/desktop_mode_floating_app_select_height"
android:layout_gravity="top|center_horizontal"
android:background="@drawable/bg_floating_desktop_select"
android:elevation="@dimen/desktop_mode_floating_app_select_elevation"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/desktop_app_select_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/desktop_mode_floating_app_select_text_margin"
android:layout_marginStart="@dimen/desktop_mode_floating_app_select_margin"
android:drawablePadding="@dimen/desktop_mode_floating_app_select_text_margin"
android:drawableStart="@drawable/ic_desktop"
android:drawableTint="?androidprv:attr/materialColorOnPrimaryContainer"
android:fontFamily="google-sans-medium"
android:gravity="center_vertical"
android:text="@string/desktop_select_app_toast"
android:textColor="?androidprv:attr/materialColorOnPrimaryContainer"
android:textSize="@dimen/desktop_mode_floating_app_select_text_size" />
<Button
android:id="@+id/close_button"
style="@android:style/Widget.DeviceDefault.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/desktop_mode_floating_app_select_margin"
android:minWidth="0dp"
android:fontFamily="google-sans-medium"
android:text="@string/desktop_button_close_app_toast"
android:textAllCaps="false"
android:textColor="?androidprv:attr/materialColorPrimary"
android:textSize="@dimen/desktop_mode_floating_app_select_text_size" />
</com.android.quickstep.views.DesktopAppSelectView>

View File

@@ -383,4 +383,12 @@
<dimen name="keyboard_quick_switch_task_view_radius">16dp</dimen>
<dimen name="keyboard_quick_switch_no_recent_items_icon_size">24dp</dimen>
<dimen name="keyboard_quick_switch_no_recent_items_icon_margin">8dp</dimen>
<!-- Desktop mode -->
<dimen name="desktop_mode_floating_app_select_height">56dp</dimen>
<dimen name="desktop_mode_floating_app_select_elevation">4dp</dimen>
<dimen name="desktop_mode_floating_app_select_margin">16dp</dimen>
<dimen name="desktop_mode_floating_app_select_text_size">14sp</dimen>
<dimen name="desktop_mode_floating_app_select_text_margin">8dp</dimen>
</resources>

View File

@@ -298,4 +298,10 @@
<!-- Accessibility label for quick switch tiles showing split tasks [CHAR LIMIT=NONE] -->
<string name="quick_switch_split_task"><xliff:g id="app_name_1" example="Chrome">%1$s</xliff:g> and <xliff:g id="app_name_2" example="Gmail">%2$s</xliff:g></string>
<!-- ******* Desktop ******* -->
<!-- Text shown in popup to choose a desktop app. [CHAR LIMIT=60] -->
<string name="desktop_select_app_toast">Adding app to Desktop</string>
<!-- Text shown on a button that closes the popup for choosing a desktop app. [CHAR_LIMIT=40] -->
<string name="desktop_button_close_app_toast">Cancel</string>
</resources>

View File

@@ -17,11 +17,9 @@ package com.android.launcher3.statehandlers;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.Nullable;
@@ -30,6 +28,7 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.views.DesktopAppSelectView;
import com.android.wm.shell.desktopmode.IDesktopTaskListener;
/**
@@ -49,6 +48,7 @@ public class DesktopVisibilityController {
@Nullable
private IDesktopTaskListener mDesktopTaskListener;
private DesktopAppSelectView mSelectAppToast;
public DesktopVisibilityController(Launcher launcher) {
mLauncher = launcher;
@@ -60,17 +60,22 @@ public class DesktopVisibilityController {
public void registerSystemUiListener() {
mDesktopTaskListener = new IDesktopTaskListener.Stub() {
@Override
public void onVisibilityChanged(int displayId, boolean visible) throws RemoteException {
public void onVisibilityChanged(int displayId, boolean visible) {
// TODO(b/261234402): move visibility from sysui state to listener
}
@Override
public void onStashedChanged(int displayId, boolean stashed) throws RemoteException {
// TODO(b/261234402): show a persistent toast
public void onStashedChanged(int displayId, boolean stashed) {
MAIN_EXECUTOR.execute(() -> {
if (stashed && displayId == mLauncher.getDisplayId()) {
Toast.makeText(mLauncher, "Adding app to Desktop",
Toast.LENGTH_SHORT).show();
if (displayId == mLauncher.getDisplayId()) {
if (DEBUG) {
Log.d(TAG, "desktop stashed changed value=" + stashed);
}
if (stashed) {
showSelectAppToast();
} else {
hideSelectAppToast();
}
}
});
}
@@ -110,6 +115,7 @@ public class DesktopVisibilityController {
if (!isDesktopModeSupported()) {
return;
}
if (freeformTasksVisible != mFreeformTasksVisible) {
mFreeformTasksVisible = freeformTasksVisible;
if (mFreeformTasksVisible) {
@@ -219,4 +225,28 @@ public class DesktopVisibilityController {
activity.setResumed();
}
}
private void showSelectAppToast() {
if (mSelectAppToast != null) {
return;
}
if (DEBUG) {
Log.d(TAG, "show toast to select desktop apps");
}
Runnable onCloseCallback = () -> {
SystemUiProxy.INSTANCE.get(mLauncher).hideStashedDesktopApps(mLauncher.getDisplayId());
};
mSelectAppToast = DesktopAppSelectView.show(mLauncher, onCloseCallback);
}
private void hideSelectAppToast() {
if (mSelectAppToast == null) {
return;
}
if (DEBUG) {
Log.d(TAG, "hide toast to select desktop apps");
}
mSelectAppToast.hide();
mSelectAppToast = null;
}
}

View File

@@ -1161,6 +1161,17 @@ public class SystemUiProxy implements ISystemUiProxy {
}
}
/** Call shell to hide desktop apps that may be stashed */
public void hideStashedDesktopApps(int displayId) {
if (mDesktopMode != null) {
try {
mDesktopMode.hideStashedDesktopApps(displayId);
} catch (RemoteException e) {
Log.w(TAG, "Failed call hideStashedDesktopApps", e);
}
}
}
/** Call shell to get number of visible freeform tasks */
public int getVisibleDesktopTaskCount(int displayId) {
if (mDesktopMode != null) {

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2023 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.quickstep.views;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
/**
* Floating view show on launcher home screen that notifies the user that an app will be launched to
* the desktop.
*/
public class DesktopAppSelectView extends LinearLayout {
private static final int HIDE_DURATION = 83;
private final Launcher mLauncher;
@Nullable
private Runnable mOnCloseCallback = null;
private boolean mIsHideAnimationRunning;
public DesktopAppSelectView(Context context) {
this(context, null);
}
public DesktopAppSelectView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DesktopAppSelectView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public DesktopAppSelectView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mLauncher = Launcher.getLauncher(context);
}
/**
* Show the popup on launcher home screen
*
* @param onCloseCallback optional callback that is called when user clicks the close button
* @return the created view
*/
public static DesktopAppSelectView show(Launcher launcher, @Nullable Runnable onCloseCallback) {
DesktopAppSelectView view = (DesktopAppSelectView) launcher.getLayoutInflater().inflate(
R.layout.floating_desktop_app_select, launcher.getDragLayer(), false);
view.setOnCloseClickCallback(onCloseCallback);
launcher.getDragLayer().addView(view);
return view;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
findViewById(R.id.close_button).setOnClickListener(v -> {
if (!mIsHideAnimationRunning) {
hide();
if (mOnCloseCallback != null) {
mOnCloseCallback.run();
}
}
});
}
/**
* Hide the floating view
*/
public void hide() {
if (!mIsHideAnimationRunning) {
mIsHideAnimationRunning = true;
animate().alpha(0).setDuration(HIDE_DURATION).setInterpolator(LINEAR).withEndAction(
() -> {
mLauncher.getDragLayer().removeView(this);
mIsHideAnimationRunning = false;
});
}
}
/**
* Add a callback that is called when close button is clicked
*/
public void setOnCloseClickCallback(@Nullable Runnable callback) {
mOnCloseCallback = callback;
}
}