Merge "Adding some tests for request pin shortcut/widget flow" into ub-launcher3-dorval
This commit is contained in:
commit
f55ad3d411
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -41,6 +41,7 @@ public class AddWidgetTest extends LauncherInstrumentationTestCase {
|
|||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
grantWidgetPermission();
|
||||
|
||||
widgetInfo = findWidgetProvider(false /* hasConfigureScreen */);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue