Add state callback in launcher
am: 4060a75d8f
Change-Id: Ib2b6336f788c14e9ee21323dedcf10f872f9e0fe
diff --git a/go/quickstep/res/drawable/default_thumbnail.xml b/go/quickstep/res/drawable/default_thumbnail.xml
new file mode 100644
index 0000000..0a2dbf0
--- /dev/null
+++ b/go/quickstep/res/drawable/default_thumbnail.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/darker_gray"/>
+ <corners android:radius="2dp"/>
+</shape>
diff --git a/go/quickstep/res/drawable/empty_content_box.xml b/go/quickstep/res/drawable/empty_content_box.xml
new file mode 100644
index 0000000..a488388
--- /dev/null
+++ b/go/quickstep/res/drawable/empty_content_box.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/transparent"/>
+ <stroke android:color="@android:color/white" android:width="4px"/>
+ <corners android:radius="2dp"/>
+</shape>
\ No newline at end of file
diff --git a/go/quickstep/src/com/android/quickstep/views/TaskItemView.java b/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
index d831b20..0a3fba8 100644
--- a/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
+++ b/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
@@ -16,8 +16,9 @@
package com.android.quickstep.views;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
@@ -25,6 +26,7 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.R;
@@ -36,14 +38,16 @@
private static final String DEFAULT_LABEL = "...";
private final Drawable mDefaultIcon;
+ private final Drawable mDefaultThumbnail;
private TextView mLabelView;
private ImageView mIconView;
private ImageView mThumbnailView;
public TaskItemView(Context context, AttributeSet attrs) {
super(context, attrs);
- mDefaultIcon = context.getResources().getDrawable(
- android.R.drawable.sym_def_app_icon, context.getTheme());
+ Resources res = context.getResources();
+ mDefaultIcon = res.getDrawable(android.R.drawable.sym_def_app_icon, context.getTheme());
+ mDefaultThumbnail = res.getDrawable(R.drawable.default_thumbnail, context.getTheme());
}
@Override
@@ -69,11 +73,7 @@
* @param label task label
*/
public void setLabel(@Nullable String label) {
- if (label == null) {
- mLabelView.setText(DEFAULT_LABEL);
- return;
- }
- mLabelView.setText(label);
+ mLabelView.setText(getSafeLabel(label));
}
/**
@@ -86,11 +86,7 @@
// The icon proper is actually smaller than the drawable and has "padding" on the side for
// the purpose of drawing the shadow, allowing the icon to pop up, so we need to scale the
// view if we want the icon to be flush with the bottom of the thumbnail.
- if (icon == null) {
- mIconView.setImageDrawable(mDefaultIcon);
- return;
- }
- mIconView.setImageDrawable(icon);
+ mIconView.setImageDrawable(getSafeIcon(icon));
}
/**
@@ -99,16 +95,23 @@
* @param thumbnail task thumbnail for the task
*/
public void setThumbnail(@Nullable Bitmap thumbnail) {
- if (thumbnail == null) {
- mThumbnailView.setImageBitmap(null);
- mThumbnailView.setBackgroundColor(Color.GRAY);
- return;
- }
- mThumbnailView.setBackgroundColor(Color.TRANSPARENT);
- mThumbnailView.setImageBitmap(thumbnail);
+ mThumbnailView.setImageDrawable(getSafeThumbnail(thumbnail));
}
public View getThumbnailView() {
return mThumbnailView;
}
+
+ private @NonNull Drawable getSafeIcon(@Nullable Drawable icon) {
+ return (icon != null) ? icon : mDefaultIcon;
+ }
+
+ private @NonNull Drawable getSafeThumbnail(@Nullable Bitmap thumbnail) {
+ return (thumbnail != null) ? new BitmapDrawable(getResources(), thumbnail)
+ : mDefaultThumbnail;
+ }
+
+ private @NonNull String getSafeLabel(@Nullable String label) {
+ return (label != null) ? label : DEFAULT_LABEL;
+ }
}
diff --git a/go/quickstep/src/com/android/quickstep/views/TaskLayerDrawable.java b/go/quickstep/src/com/android/quickstep/views/TaskLayerDrawable.java
new file mode 100644
index 0000000..3a23048
--- /dev/null
+++ b/go/quickstep/src/com/android/quickstep/views/TaskLayerDrawable.java
@@ -0,0 +1,90 @@
+/*
+ * 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.quickstep.views;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.R;
+
+/**
+ * A layer drawable for task content that transitions between two drawables by crossfading. Similar
+ * to {@link android.graphics.drawable.TransitionDrawable} but allows callers to control transition
+ * progress and provides a default, empty drawable.
+ */
+public final class TaskLayerDrawable extends LayerDrawable {
+ private final Drawable mEmptyDrawable;
+
+ public TaskLayerDrawable(Context context) {
+ super(new Drawable[0]);
+
+ // Use empty drawable for both layers initially.
+ mEmptyDrawable = context.getResources().getDrawable(
+ R.drawable.empty_content_box, context.getTheme());
+ addLayer(mEmptyDrawable);
+ addLayer(mEmptyDrawable);
+ setTransitionProgress(1.0f);
+ }
+
+ /**
+ * Immediately set the front-most drawable layer.
+ *
+ * @param drawable drawable to set
+ */
+ public void setCurrentDrawable(@NonNull Drawable drawable) {
+ setDrawable(0, drawable);
+ }
+
+ /**
+ * Immediately reset the drawable to showing the empty drawable.
+ */
+ public void resetDrawable() {
+ setCurrentDrawable(mEmptyDrawable);
+ }
+
+ /**
+ * Prepare to start animating the transition by pushing the current drawable to the back and
+ * setting a new drawable to the front layer and making it invisible.
+ *
+ * @param endDrawable drawable to animate to
+ */
+ public void startNewTransition(@NonNull Drawable endDrawable) {
+ Drawable oldDrawable = getDrawable(0);
+ setDrawable(1, oldDrawable);
+ setDrawable(0, endDrawable);
+ setTransitionProgress(0.0f);
+ }
+
+ /**
+ * Set the progress of the transition animation to crossfade the two drawables.
+ *
+ * @param progress current transition progress between 0 (front view invisible) and 1
+ * (front view visible)
+ */
+ public void setTransitionProgress(float progress) {
+ if (progress > 1 || progress < 0) {
+ throw new IllegalArgumentException("Transition progress should be between 0 and 1");
+ }
+ int drawableAlpha = (int) (progress * 255);
+ getDrawable(0).setAlpha(drawableAlpha);
+ getDrawable(1).setAlpha(255 - drawableAlpha);
+ invalidateSelf();
+ }
+}
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 089d672..3686493 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -18,39 +18,39 @@
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.launcher3.tests">
- <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
+ <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
<application android:debuggable="true">
- <uses-library android:name="android.test.runner" />
+ <uses-library android:name="android.test.runner"/>
<receiver
android:name="com.android.launcher3.testcomponent.AppWidgetNoConfig"
android:label="No Config">
<intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider"
- android:resource="@xml/appwidget_no_config" />
+ android:resource="@xml/appwidget_no_config"/>
</receiver>
<receiver
android:name="com.android.launcher3.testcomponent.AppWdigetHidden"
android:label="Hidden widget">
<intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider"
- android:resource="@xml/appwidget_hidden" />
+ android:resource="@xml/appwidget_hidden"/>
</receiver>
<receiver
android:name="com.android.launcher3.testcomponent.AppWidgetWithConfig"
android:label="With Config">
<intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider"
- android:resource="@xml/appwidget_with_config" />
+ android:resource="@xml/appwidget_with_config"/>
</receiver>
<activity
@@ -61,8 +61,8 @@
</activity>
<activity
android:name="com.android.launcher3.testcomponent.RequestPinItemActivity"
- android:label="Test Pin Item"
- android:icon="@drawable/test_drawable_pin_item">
+ android:icon="@drawable/test_drawable_pin_item"
+ android:label="Test Pin Item">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@@ -73,28 +73,28 @@
<provider
android:name="com.android.launcher3.testcomponent.TestCommandReceiver"
android:authorities="${packageName}.commands"
- android:exported="true" />
+ android:exported="true"/>
<activity
android:name="com.android.launcher3.testcomponent.TestLauncherActivity"
- android:launchMode="singleTask"
android:clearTaskOnLaunch="true"
- android:label="Test launcher"
- android:stateNotNeeded="true"
- android:theme="@android:style/Theme.DeviceDefault.Light"
- android:windowSoftInputMode="adjustPan"
- android:screenOrientation="unspecified"
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
- android:resizeableActivity="true"
- android:taskAffinity=""
+ android:enabled="false"
+ android:label="Test launcher"
+ android:launchMode="singleTask"
android:process=":testLauncherProcess"
- android:enabled="false">
+ android:resizeableActivity="true"
+ android:screenOrientation="unspecified"
+ android:stateNotNeeded="true"
+ android:taskAffinity=""
+ android:theme="@android:style/Theme.DeviceDefault.Light"
+ android:windowSoftInputMode="adjustPan">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.HOME" />
- <category android:name="android.intent.category.DEFAULT" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.HOME"/>
+ <category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.MONKEY"/>
- <category android:name="android.intent.category.LAUNCHER_APP" />
+ <category android:name="android.intent.category.LAUNCHER_APP"/>
</intent-filter>
</activity>
<activity
@@ -104,6 +104,12 @@
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
+ <intent-filter>
+ <action android:name="com.android.launcher3.intent.action.test_shortcut"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ <meta-data android:name="android.app.shortcuts"
+ android:resource="@xml/shortcuts"/>
</activity>
</application>
</manifest>
diff --git a/tests/res/values/strings.xml b/tests/res/values/strings.xml
new file mode 100644
index 0000000..0ad87fb
--- /dev/null
+++ b/tests/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="shortcut1" translatable="false">Shortcut 1</string>
+ <string name="shortcut2" translatable="false">Shortcut 2</string>
+ <string name="shortcut3" translatable="false">Shortcut 3</string>
+</resources>
diff --git a/tests/res/xml/shortcuts.xml b/tests/res/xml/shortcuts.xml
new file mode 100644
index 0000000..bdc22f9
--- /dev/null
+++ b/tests/res/xml/shortcuts.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+ <shortcut
+ android:shortcutId="shortcut1"
+ android:shortcutShortLabel="@string/shortcut1">
+ <intent android:action="com.android.launcher3.intent.action.test_shortcut"/>
+ </shortcut>
+ <shortcut
+ android:shortcutId="shortcut2"
+ android:shortcutShortLabel="@string/shortcut2">
+ <intent android:action="com.android.launcher3.intent.action.test_shortcut"/>
+ </shortcut>
+ <shortcut
+ android:shortcutId="shortcut3"
+ android:shortcutShortLabel="@string/shortcut3">
+ <intent android:action="com.android.launcher3.intent.action.test_shortcut"/>
+ </shortcut>
+</shortcuts>
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index e11e62e..c1727cc 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -25,7 +25,6 @@
import static org.junit.Assert.assertTrue;
import android.content.Intent;
-import android.content.pm.LauncherActivityInfo;
import android.util.Log;
import androidx.test.filters.LargeTest;
@@ -62,6 +61,7 @@
@RunWith(AndroidJUnit4.class)
public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
private static final String TAG = "TaplTestsAosp";
+ private static final String APP_NAME = "LauncherTestApp";
private static int sScreenshotCount = 0;
@@ -307,12 +307,11 @@
@PortraitLandscape
public void testLaunchMenuItem() throws Exception {
if (!TestHelpers.isInLauncherProcess()) return;
- final LauncherActivityInfo testApp = getSettingsApp();
final AppIconMenu menu = mLauncher.
getWorkspace().
switchToAllApps().
- getAppIcon(testApp.getLabel().toString()).
+ getAppIcon(APP_NAME).
openMenu();
executeOnLauncher(
@@ -322,7 +321,7 @@
final AppIconMenuItem menuItem = menu.getMenuItem(1);
final String itemName = menuItem.getText();
- menuItem.launch(testApp.getComponentName().getPackageName(), itemName);
+ menuItem.launch(getAppPackageName(), APP_NAME);
}
@Test
@@ -330,16 +329,15 @@
public void testDragAppIcon() throws Throwable {
try {
TestProtocol.sDebugTracing = true;
- final String appName = "LauncherTestApp";
// 1. Open all apps and wait for load complete.
// 2. Drag icon to homescreen.
// 3. Verify that the icon works on homescreen.
mLauncher.getWorkspace().
switchToAllApps().
- getAppIcon(appName).
+ getAppIcon(APP_NAME).
dragToWorkspace().
- getWorkspaceAppIcon(appName).
- launch(getInstrumentation().getContext().getPackageName());
+ getWorkspaceAppIcon(APP_NAME).
+ launch(getAppPackageName(), APP_NAME);
} finally {
TestProtocol.sDebugTracing = false;
}
@@ -349,7 +347,6 @@
@PortraitLandscape
public void testDragShortcut() throws Throwable {
if (!TestHelpers.isInLauncherProcess()) return;
- LauncherActivityInfo testApp = getSettingsApp();
// 1. Open all apps and wait for load complete.
// 2. Find the app and long press it to show shortcuts.
@@ -357,7 +354,7 @@
final AppIconMenuItem menuItem = mLauncher.
getWorkspace().
switchToAllApps().
- getAppIcon(testApp.getLabel().toString()).
+ getAppIcon(APP_NAME).
openMenu().
getMenuItem(0);
final String shortcutName = menuItem.getText();
@@ -368,6 +365,10 @@
menuItem.
dragToWorkspace().
getWorkspaceAppIcon(shortcutName).
- launch(testApp.getComponentName().getPackageName(), shortcutName);
+ launch(getAppPackageName(), APP_NAME);
+ }
+
+ private static String getAppPackageName() {
+ return getInstrumentation().getContext().getPackageName();
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index fbeb3a2..44fc3f7 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -50,4 +50,9 @@
downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, iconCenter);
return new AppIconMenu(mLauncher, deepShortcutsContainer);
}
+
+ @Override
+ protected String getLongPressIndicator() {
+ return "deep_shortcuts_container";
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java b/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
index c39f8d1..ba9c10e 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
@@ -32,4 +32,9 @@
public String getText() {
return mObject.getText();
}
+
+ @Override
+ protected String getLongPressIndicator() {
+ return "drop_target_bar";
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 16ddba8..d940412 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -27,7 +27,7 @@
/**
* Ancestor for AppIcon and AppMenuItem.
*/
-class Launchable {
+abstract class Launchable {
protected final LauncherInstrumentation mLauncher;
protected final UiObject2 mObject;
@@ -76,10 +76,13 @@
Workspace.dragIconToWorkspace(
mLauncher,
this,
- new Point(device.getDisplayWidth() / 2, device.getDisplayHeight() / 2));
+ new Point(device.getDisplayWidth() / 2, device.getDisplayHeight() / 2),
+ getLongPressIndicator());
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"dragged launchable to workspace")) {
return new Workspace(mLauncher);
}
}
+
+ protected abstract String getLongPressIndicator();
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 943332e..46562ce 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -118,7 +118,7 @@
mLauncher,
getHotseatAppIcon("Chrome"),
new Point(mLauncher.getDevice().getDisplayWidth(),
- workspace.getVisibleBounds().centerY()));
+ workspace.getVisibleBounds().centerY()), "deep_shortcuts_container");
verifyActiveContainer();
}
assertTrue("Home screen workspace didn't become scrollable",
@@ -136,12 +136,13 @@
}
static void dragIconToWorkspace(
- LauncherInstrumentation launcher, Launchable launchable, Point dest) {
+ LauncherInstrumentation launcher, Launchable launchable, Point dest,
+ String longPressIndicator) {
LauncherInstrumentation.log("dragIconToWorkspace: begin");
final Point launchableCenter = launchable.getObject().getVisibleCenter();
final long downTime = SystemClock.uptimeMillis();
launcher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, launchableCenter);
- launcher.waitForLauncherObject("deep_shortcuts_container");
+ launcher.waitForLauncherObject(longPressIndicator);
launcher.movePointer(downTime, DRAG_DURACTION, launchableCenter, dest);
launcher.sendPointer(
downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest);