Merge "Adding some tests for request pin shortcut/widget flow" into ub-launcher3-dorval

This commit is contained in:
TreeHugger Robot 2017-02-22 23:53:26 +00:00 committed by Android (Google) Code Review
commit f55ad3d411
12 changed files with 575 additions and 70 deletions

View File

@ -23,7 +23,9 @@
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
<receiver android:name="com.android.launcher3.testcomponent.AppWidgetNoConfig">
<receiver
android:name="com.android.launcher3.testcomponent.AppWidgetNoConfig"
android:label="No Config">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@ -31,7 +33,9 @@
android:resource="@xml/appwidget_no_config" />
</receiver>
<receiver android:name="com.android.launcher3.testcomponent.AppWidgetWithConfig">
<receiver
android:name="com.android.launcher3.testcomponent.AppWidgetWithConfig"
android:label="With Config">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@ -45,5 +49,15 @@
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
<activity
android:name="com.android.launcher3.testcomponent.RequestPinItemActivity"
android:label="Test Pin Item"
android:icon="@drawable/test_drawable_pin_item">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2017 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.
-->
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
android:fillColor="#66000000"
android:pathData="M0,24a24,24 0 1,0 48,0a24,24 0 1,0 -48,0"/>
<path
android:fillColor="#FF1B5E20"
android:pathData="M2,24a22,22 0 1,0 44,0a22,22 0 1,0 -44,0"/>
<group
android:translateX="12"
android:translateY="12">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12Z"/>
</group>
</vector>

View File

@ -0,0 +1,126 @@
/*
* Copyright (C) 2017 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.launcher3.testcomponent;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* Base activity with utility methods to help automate testing.
*/
public class BaseTestingActivity extends Activity implements View.OnClickListener {
public static final String SUFFIX_COMMAND = "-command";
public static final String EXTRA_METHOD = "method";
public static final String EXTRA_PARAM = "param_";
private static final int MARGIN_DP = 20;
private final String mAction = this.getClass().getName();
private LinearLayout mView;
private int mMargin;
private final BroadcastReceiver mCommandReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
handleCommand(intent);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMargin = Math.round(TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, MARGIN_DP, getResources().getDisplayMetrics()));
mView = new LinearLayout(this);
mView.setPadding(mMargin, mMargin, mMargin, mMargin);
mView.setOrientation(LinearLayout.VERTICAL);
setContentView(mView);
registerReceiver(mCommandReceiver, new IntentFilter(mAction + SUFFIX_COMMAND));
}
protected void addButton(String title, String method) {
Button button = new Button(this);
button.setText(title);
button.setTag(method);
button.setOnClickListener(this);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
lp.bottomMargin = mMargin;
mView.addView(button, lp);
}
@Override
protected void onResume() {
super.onResume();
sendBroadcast(new Intent(mAction).putExtra(Intent.EXTRA_INTENT, getIntent()));
}
@Override
protected void onDestroy() {
unregisterReceiver(mCommandReceiver);
super.onDestroy();
}
@Override
public void onClick(View view) {
handleCommand(new Intent().putExtra(EXTRA_METHOD, (String) view.getTag()));
}
private void handleCommand(Intent cmd) {
String methodName = cmd.getStringExtra(EXTRA_METHOD);
try {
Method method = null;
for (Method m : this.getClass().getDeclaredMethods()) {
if (methodName.equals(m.getName()) &&
!Modifier.isStatic(m.getModifiers()) &&
Modifier.isPublic(m.getModifiers())) {
method = m;
break;
}
}
Object[] args = new Object[method.getParameterTypes().length];
Bundle extras = cmd.getExtras();
for (int i = 0; i < args.length; i++) {
args[i] = extras.get(EXTRA_PARAM + i);
}
method.invoke(this, args);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static Intent getCommandIntent(Class<?> clazz, String method) {
return new Intent(clazz.getName() + SUFFIX_COMMAND)
.putExtra(EXTRA_METHOD, method);
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2017 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.launcher3.testcomponent;
import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.IntentSender;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Icon;
import android.os.Bundle;
/**
* Sample activity to request pinning an item.
*/
@TargetApi(26)
public class RequestPinItemActivity extends BaseTestingActivity {
private PendingIntent mCallback = null;
private String mShortcutId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addButton("Pin Shortcut", "pinShortcut");
addButton("Pin Widget without config ", "pinWidgetNoConfig");
addButton("Pin Widget with config", "pinWidgetWithConfig");
}
public void setCallback(PendingIntent callback) {
mCallback = callback;
}
public void setShortcutId(String id) {
mShortcutId = id;
}
public void pinShortcut() {
ShortcutManager sm = getSystemService(ShortcutManager.class);
// Generate icon
int r = sm.getIconMaxWidth() / 2;
Bitmap icon = Bitmap.createBitmap(r * 2, r * 2, Bitmap.Config.ARGB_8888);
Paint p = new Paint();
p.setColor(Color.RED);
new Canvas(icon).drawCircle(r, r, r, p);
ShortcutInfo info = new ShortcutInfo.Builder(this, mShortcutId)
.setIntent(getPackageManager().getLaunchIntentForPackage(getPackageName()))
.setIcon(Icon.createWithBitmap(icon))
.setShortLabel("Test shortcut")
.build();
IntentSender callback = mCallback == null ? null : mCallback.getIntentSender();
sm.requestPinShortcut(info, callback);
}
public void pinWidgetNoConfig() {
requestWidget(new ComponentName(this, AppWidgetNoConfig.class));
}
public void pinWidgetWithConfig() {
requestWidget(new ComponentName(this, AppWidgetWithConfig.class));
}
private void requestWidget(ComponentName cn) {
AppWidgetManager.getInstance(this).requestPinAppWidget(cn, mCallback);
}
}

View File

@ -15,50 +15,30 @@
*/
package com.android.launcher3.testcomponent;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
/**
* Simple activity for widget configuration
*/
public class WidgetConfigActivity extends Activity {
public class WidgetConfigActivity extends BaseTestingActivity {
public static final String SUFFIX_FINISH = "-finish";
public static final String EXTRA_CODE = "code";
public static final String EXTRA_INTENT = "intent";
private final BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
WidgetConfigActivity.this.setResult(
intent.getIntExtra(EXTRA_CODE, RESULT_CANCELED),
(Intent) intent.getParcelableExtra(EXTRA_INTENT));
WidgetConfigActivity.this.finish();
}
};
private final String mAction = this.getClass().getName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
registerReceiver(mFinishReceiver, new IntentFilter(mAction + SUFFIX_FINISH));
addButton("Cancel", "clickCancel");
addButton("OK", "clickOK");
}
@Override
protected void onResume() {
super.onResume();
sendBroadcast(new Intent(mAction).putExtra(Intent.EXTRA_INTENT, getIntent()));
public void clickCancel() {
setResult(RESULT_CANCELED);
finish();
}
@Override
protected void onDestroy() {
unregisterReceiver(mFinishReceiver);
super.onDestroy();
public void clickOK() {
setResult(RESULT_OK);
finish();
}
}

View File

@ -22,6 +22,7 @@ public class AllAppsIconToHomeTest extends LauncherInstrumentationTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
setDefaultLauncher();
mSettingsApp = LauncherAppsCompat.getInstance(mTargetContext)
.getActivityList("com.android.settings", Process.myUserHandle()).get(0);

View File

@ -15,10 +15,14 @@
*/
package com.android.launcher3.ui;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Point;
import android.os.ParcelFileDescriptor;
import android.os.Process;
@ -46,16 +50,24 @@ import com.android.launcher3.testcomponent.AppWidgetNoConfig;
import com.android.launcher3.testcomponent.AppWidgetWithConfig;
import com.android.launcher3.util.ManagedProfileHeuristic;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Base class for all instrumentation tests providing various utility methods.
*/
public class LauncherInstrumentationTestCase extends InstrumentationTestCase {
public static final long DEFAULT_ACTIVITY_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 5;
public static final long DEFAULT_UI_TIMEOUT = 3000;
public static final long DEFAULT_WORKER_TIMEOUT_SECS = 5;
@ -89,11 +101,14 @@ public class LauncherInstrumentationTestCase extends InstrumentationTestCase {
* Starts the launcher activity in the target package and returns the Launcher instance.
*/
protected Launcher startLauncher() {
Intent homeIntent = new Intent(Intent.ACTION_MAIN)
return (Launcher) getInstrumentation().startActivitySync(getHomeIntent());
}
protected Intent getHomeIntent() {
return new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setPackage(mTargetPackage)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return (Launcher) getInstrumentation().startActivitySync(homeIntent);
}
/**
@ -104,15 +119,30 @@ public class LauncherInstrumentationTestCase extends InstrumentationTestCase {
if (mTargetContext.getPackageManager().checkPermission(
mTargetPackage, android.Manifest.permission.BIND_APPWIDGET)
!= PackageManager.PERMISSION_GRANTED) {
ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation().executeShellCommand(
"appwidget grantbind --package " + mTargetPackage);
// Read the input stream fully.
FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
while (fis.read() != -1);
fis.close();
runShellCommand("appwidget grantbind --package " + mTargetPackage);
}
}
/**
* Sets the target launcher as default launcher.
*/
protected void setDefaultLauncher() throws IOException {
ActivityInfo launcher = mTargetContext.getPackageManager()
.queryIntentActivities(getHomeIntent(), 0).get(0).activityInfo;
runShellCommand("cmd package set-home-activity " +
new ComponentName(launcher.packageName, launcher.name).flattenToString());
}
protected void runShellCommand(String command) throws IOException {
ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
.executeShellCommand(command);
// Read the input stream fully.
FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
while (fis.read() != -1);
fis.close();
}
/**
* Opens all apps and returns the recycler view
*/
@ -284,4 +314,35 @@ public class LauncherInstrumentationTestCase extends InstrumentationTestCase {
String name = mTargetContext.getResources().getResourceEntryName(id);
return By.res(mTargetPackage, name);
}
/**
* Broadcast receiver which blocks until the result is received.
*/
public class BlockingBroadcastReceiver extends BroadcastReceiver {
private final CountDownLatch latch = new CountDownLatch(1);
private Intent mIntent;
public BlockingBroadcastReceiver(String action) {
mTargetContext.registerReceiver(this, new IntentFilter(action));
}
@Override
public void onReceive(Context context, Intent intent) {
mIntent = intent;
latch.countDown();
}
public Intent blockingGetIntent() throws InterruptedException {
latch.await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS);
mTargetContext.unregisterReceiver(this);
return mIntent;
}
public Intent blockingGetExtraIntent() throws InterruptedException {
Intent intent = blockingGetIntent();
return intent == null ? null : (Intent) intent.getParcelableExtra(Intent.EXTRA_INTENT);
}
}
}

View File

@ -25,6 +25,7 @@ public class ShortcutsLaunchTest extends LauncherInstrumentationTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
setDefaultLauncher();
mSettingsApp = LauncherAppsCompat.getInstance(mTargetContext)
.getActivityList("com.android.settings", Process.myUserHandle()).get(0);

View File

@ -25,6 +25,7 @@ public class ShortcutsToHomeTest extends LauncherInstrumentationTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
setDefaultLauncher();
mSettingsApp = LauncherAppsCompat.getInstance(mTargetContext)
.getActivityList("com.android.settings", Process.myUserHandle()).get(0);

View File

@ -18,10 +18,7 @@ package com.android.launcher3.ui.widget;
import android.app.Activity;
import android.app.Application;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
import android.test.suitebuilder.annotation.LargeTest;
@ -41,8 +38,6 @@ import com.android.launcher3.util.Wait;
import com.android.launcher3.widget.WidgetCell;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Test to verify widget configuration is properly shown.
@ -50,9 +45,6 @@ import java.util.concurrent.TimeUnit;
@LargeTest
public class AddConfigWidgetTest extends LauncherInstrumentationTestCase {
public static final long DEFAULT_ACTIVITY_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 5;
private LauncherAppWidgetProviderInfo mWidgetInfo;
private SimpleActivityMonitor mActivityMonitor;
private MainThreadExecutor mMainThreadExecutor;
@ -69,6 +61,8 @@ public class AddConfigWidgetTest extends LauncherInstrumentationTestCase {
.registerActivityLifecycleCallbacks(mActivityMonitor);
mMainThreadExecutor = new MainThreadExecutor();
mAppWidgetManager = AppWidgetManager.getInstance(mTargetContext);
grantWidgetPermission();
}
@Override
@ -126,12 +120,11 @@ public class AddConfigWidgetTest extends LauncherInstrumentationTestCase {
// Verify that the widget id is valid and bound
assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
setResult(acceptConfig);
if (acceptConfig) {
setResult(Activity.RESULT_OK);
assertTrue(Wait.atMost(new WidgetSearchCondition(), DEFAULT_ACTIVITY_TIMEOUT));
assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
} else {
setResult(Activity.RESULT_CANCELED);
// Verify that the widget id is deleted.
assertTrue(Wait.atMost(new Condition() {
@Override
@ -142,10 +135,11 @@ public class AddConfigWidgetTest extends LauncherInstrumentationTestCase {
}
}
private void setResult(int resultCode) {
String action = WidgetConfigActivity.class.getName() + WidgetConfigActivity.SUFFIX_FINISH;
private void setResult(boolean success) {
getInstrumentation().getTargetContext().sendBroadcast(
new Intent(action).putExtra(WidgetConfigActivity.EXTRA_CODE, resultCode));
WidgetConfigActivity.getCommandIntent(WidgetConfigActivity.class,
success ? "clickOK" : "clickCancel"));
}
/**
@ -185,28 +179,17 @@ public class AddConfigWidgetTest extends LauncherInstrumentationTestCase {
/**
* Broadcast receiver for receiving widget config activity status.
*/
private class WidgetConfigStartupMonitor extends BroadcastReceiver {
private class WidgetConfigStartupMonitor extends BlockingBroadcastReceiver {
private final CountDownLatch latch = new CountDownLatch(1);
private Intent mIntent;
WidgetConfigStartupMonitor() {
getInstrumentation().getTargetContext().registerReceiver(this,
new IntentFilter(WidgetConfigActivity.class.getName()));
}
@Override
public void onReceive(Context context, Intent intent) {
mIntent = intent.getParcelableExtra(Intent.EXTRA_INTENT);
latch.countDown();
public WidgetConfigStartupMonitor() {
super(WidgetConfigActivity.class.getName());
}
public int getWidgetId() throws InterruptedException {
latch.await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS);
getInstrumentation().getTargetContext().unregisterReceiver(this);
assertNotNull(mIntent);
assertEquals(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE, mIntent.getAction());
int widgetId = mIntent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
Intent intent = blockingGetExtraIntent();
assertNotNull(intent);
assertEquals(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE, intent.getAction());
int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
LauncherAppWidgetInfo.NO_ID);
assertNotSame(widgetId, LauncherAppWidgetInfo.NO_ID);
return widgetId;

View File

@ -41,6 +41,7 @@ public class AddWidgetTest extends LauncherInstrumentationTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
grantWidgetPermission();
widgetInfo = findWidgetProvider(false /* hasConfigureScreen */);
}

View File

@ -0,0 +1,210 @@
/*
* Copyright (C) 2017 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.launcher3.ui.widget;
import android.app.Activity;
import android.app.Application;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.test.suitebuilder.annotation.LargeTest;
import android.view.View;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.testcomponent.AppWidgetNoConfig;
import com.android.launcher3.testcomponent.AppWidgetWithConfig;
import com.android.launcher3.testcomponent.RequestPinItemActivity;
import com.android.launcher3.ui.LauncherInstrumentationTestCase;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.SimpleActivityMonitor;
import com.android.launcher3.util.Wait;
import com.android.launcher3.widget.WidgetCell;
import java.util.UUID;
import java.util.concurrent.Callable;
/**
* Test to verify pin item request flow.
*/
@LargeTest
public class RequestPinItemTest extends LauncherInstrumentationTestCase {
private SimpleActivityMonitor mActivityMonitor;
private MainThreadExecutor mMainThreadExecutor;
private String mCallbackAction;
private String mShortcutId;
private int mAppWidgetId;
@Override
protected void setUp() throws Exception {
super.setUp();
grantWidgetPermission();
setDefaultLauncher();
mActivityMonitor = new SimpleActivityMonitor();
((Application) getInstrumentation().getTargetContext().getApplicationContext())
.registerActivityLifecycleCallbacks(mActivityMonitor);
mMainThreadExecutor = new MainThreadExecutor();
mCallbackAction = UUID.randomUUID().toString();
mShortcutId = UUID.randomUUID().toString();
}
@Override
protected void tearDown() throws Exception {
((Application) getInstrumentation().getTargetContext().getApplicationContext())
.unregisterActivityLifecycleCallbacks(mActivityMonitor);
super.tearDown();
}
public void testPinWidgetNoConfig() throws Throwable {
runTest("pinWidgetNoConfig", true, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View view) {
return info instanceof LauncherAppWidgetInfo &&
((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
((LauncherAppWidgetInfo) info).providerName.getClassName()
.equals(AppWidgetNoConfig.class.getName());
}
});
}
public void testPinWidgetWithConfig() throws Throwable {
runTest("pinWidgetWithConfig", true, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View view) {
return info instanceof LauncherAppWidgetInfo &&
((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
((LauncherAppWidgetInfo) info).providerName.getClassName()
.equals(AppWidgetWithConfig.class.getName());
}
});
}
public void testPinWidgetShortcut() throws Throwable {
runTest("pinShortcut", false, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View view) {
return info instanceof ShortcutInfo &&
info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
ShortcutKey.fromItemInfo(info).getId().equals(mShortcutId);
}
});
}
private void runTest(String activityMethod, boolean isWidget, ItemOperator itemMatcher)
throws Throwable {
if (!Utilities.isAtLeastO()) {
return;
}
lockRotation(true);
clearHomescreen();
startLauncher();
// Open all apps and wait for load complete
final UiObject2 appsContainer = openAllApps();
assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
// Open Pin item activity
BlockingBroadcastReceiver openMonitor = new BlockingBroadcastReceiver(
RequestPinItemActivity.class.getName());
scrollAndFind(appsContainer, By.text("Test Pin Item")).click();
assertNotNull(openMonitor.blockingGetExtraIntent());
// Set callback
PendingIntent callback = PendingIntent.getBroadcast(mTargetContext, 0,
new Intent(mCallbackAction), PendingIntent.FLAG_ONE_SHOT);
mTargetContext.sendBroadcast(RequestPinItemActivity.getCommandIntent(
RequestPinItemActivity.class, "setCallback").putExtra(
RequestPinItemActivity.EXTRA_PARAM + "0", callback));
if (!isWidget) {
// Set shortcut id
mTargetContext.sendBroadcast(RequestPinItemActivity.getCommandIntent(
RequestPinItemActivity.class, "setShortcutId").putExtra(
RequestPinItemActivity.EXTRA_PARAM + "0", mShortcutId));
}
// call the requested method to start the flow
mTargetContext.sendBroadcast(RequestPinItemActivity.getCommandIntent(
RequestPinItemActivity.class, activityMethod));
UiObject2 widgetCell = mDevice.wait(
Until.findObject(By.clazz(WidgetCell.class)), DEFAULT_ACTIVITY_TIMEOUT);
assertNotNull(widgetCell);
// Accept confirmation:
BlockingBroadcastReceiver resultReceiver = new BlockingBroadcastReceiver(mCallbackAction);
mDevice.wait(Until.findObject(By.text(mTargetContext.getString(
R.string.place_automatically).toUpperCase())), DEFAULT_UI_TIMEOUT).click();
Intent result = resultReceiver.blockingGetIntent();
assertNotNull(result);
mAppWidgetId = result.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
if (isWidget) {
assertNotSame(-1, mAppWidgetId);
}
// Go back to home
mTargetContext.startActivity(getHomeIntent());
assertTrue(Wait.atMost(new ItemSearchCondition(itemMatcher), DEFAULT_ACTIVITY_TIMEOUT));
}
/**
* Condition for for an item
*/
private class ItemSearchCondition extends Condition implements Callable<Boolean> {
private final ItemOperator mOp;
ItemSearchCondition(ItemOperator op) {
mOp = op;
}
@Override
public boolean isTrue() throws Throwable {
return mMainThreadExecutor.submit(this).get();
}
@Override
public Boolean call() throws Exception {
// Find the resumed launcher
Launcher launcher = null;
for (Activity a : mActivityMonitor.resumed) {
if (a instanceof Launcher) {
launcher = (Launcher) a;
}
}
if (launcher == null) {
return false;
}
return launcher.getWorkspace().getFirstMatch(mOp) != null;
}
}
}