Adding a widget to perform a few basic tests of the widget framework
Change-Id: I5180696ab6d08bc1461c6bd796a24f65416a07b9
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 7bf8387..d81abee 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -433,6 +433,29 @@
</intent-filter>
</activity-alias>
+ <activity android:name=".widget.WidgetTestActivity"
+ android:label="@string/widget_framework_test">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_other" />
+ </activity>
+
+ <receiver android:name=".widget.WidgetCtsProvider">
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ </intent-filter>
+ <!-- This specifies the widget provider info -->
+ <meta-data android:name="android.appwidget.provider"
+ android:resource="@xml/widget_info" />
+ </receiver>
+
+ <!-- The service serving the RemoteViews to the collection widget -->
+ <service android:name=".widget.WidgetCtsService"
+ android:permission="android.permission.BIND_REMOTEVIEWS"
+ android:exported="false" />
+
</application>
</manifest>
diff --git a/apps/CtsVerifier/res/layout/list_item.xml b/apps/CtsVerifier/res/layout/list_item.xml
new file mode 100644
index 0000000..7fd9002
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/list_item.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/list_item_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:gravity="center"
+ android:fontFamily="sans-serif-light"
+ android:textSize="14dp"
+ android:freezesText="true"
+ android:background="#ff1f1f1f" />
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/pass_fail_widget.xml b/apps/CtsVerifier/res/layout/pass_fail_widget.xml
new file mode 100644
index 0000000..31691cc
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/pass_fail_widget.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <include android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ layout="@layout/pass_fail_buttons" />
+
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/widget_layout.xml b/apps/CtsVerifier/res/layout/widget_layout.xml
new file mode 100644
index 0000000..4e2a6b6
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/widget_layout.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/widget_margin_top"
+ android:layout_marginBottom="@dimen/widget_margin_bottom"
+ android:layout_marginLeft="@dimen/widget_margin_left"
+ android:layout_marginRight="@dimen/widget_margin_right"
+ android:padding="1dp"
+ android:background="#2f2f2f">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingLeft="12dp"
+ android:paddingTop="12dp"
+ android:paddingBottom="12dp"
+ android:paddingRight="12dp"
+ android:layout_gravity="center"
+ android:background="#222">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="top|left"
+ android:layout_marginBottom="10dp"
+ android:fontFamily="sans-serif"
+ android:textSize="20sp"
+ android:text="@string/widget_name"
+ android:freezesText="true"/>
+
+ <TextView
+ android:id="@+id/instruction"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="20dp"
+ android:fontFamily="sans-serif-light"
+ android:textSize="16sp"
+ android:freezesText="true"/>
+
+ <TextView
+ android:id="@+id/data"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="18dp"
+ android:layout_gravity="center_horizontal"
+ android:fontFamily="sans-serif-light"
+ android:textSize="16sp"/>
+
+ <ListView
+ android:id="@+id/list"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:layout_marginBottom="12dp"
+ android:padding="1dp"
+ android:background="#333"
+ android:visibility="gone"/>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|center_horizontal"
+ android:orientation="horizontal">
+ <Button
+ android:id="@+id/fail"
+ android:layout_marginRight="8dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="100dp"
+ android:text="@string/widget_fail" />
+ <Button
+ android:id="@+id/pass"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="100dp"
+ android:text="@string/widget_pass" />
+ </LinearLayout>
+
+ </LinearLayout>
+</FrameLayout>
diff --git a/apps/CtsVerifier/res/values-v14/dimens.xml b/apps/CtsVerifier/res/values-v14/dimens.xml
new file mode 100644
index 0000000..8b5494e
--- /dev/null
+++ b/apps/CtsVerifier/res/values-v14/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+<resources>
+ <dimen name="widget_margin_top">0dp</dimen>
+ <dimen name="widget_margin_bottom">0dp</dimen>
+ <dimen name="widget_margin_left">0dp</dimen>
+ <dimen name="widget_margin_right">0dp</dimen>
+</resources>
diff --git a/apps/CtsVerifier/res/values/dimens.xml b/apps/CtsVerifier/res/values/dimens.xml
new file mode 100644
index 0000000..00257a9
--- /dev/null
+++ b/apps/CtsVerifier/res/values/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+<resources>
+ <dimen name="widget_margin_top">8dp</dimen>
+ <dimen name="widget_margin_bottom">8dp</dimen>
+ <dimen name="widget_margin_left">8dp</dimen>
+ <dimen name="widget_margin_right">8dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index c6f74cf..925151c 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -579,4 +579,12 @@
<string name="camera_fov_enable_compass_mode_description">If enabled, the panorama orients
itself according to the current rotation of the device.</string>
+ <!-- Strings for Widget -->
+ <string name="widget_framework_test">Widget Framework Test</string>
+ <string name="widget_framework_test_info">This test checks some basic features of the widget
+ framework. In order to perform the test, press the Home button. Add the widget
+ titled "CTS Verifier" to the home screen. Follow the instructions in the widget.</string>
+ <string name="widget_name">Widget Framework Test</string>
+ <string name="widget_pass">Pass</string>
+ <string name="widget_fail">Fail</string>
</resources>
diff --git a/apps/CtsVerifier/res/xml/widget_info.xml b/apps/CtsVerifier/res/xml/widget_info.xml
new file mode 100644
index 0000000..f875446
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/widget_info.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+<appwidget-provider
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:minWidth="250dp"
+ android:minHeight="360dp"
+ android:updatePeriodMillis="1800000"
+ android:initialLayout="@layout/widget_layout"
+ android:resizeMode="vertical|horizontal"
+ android:minResizeWidth="40dp"
+ android:minResizeHeight="40dp"
+ android:widgetCategory="keyguard|home_screen">
+</appwidget-provider>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetCtsProvider.java b/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetCtsProvider.java
new file mode 100644
index 0000000..74146f1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetCtsProvider.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2013 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.cts.verifier.widget;
+
+import java.util.HashMap;
+
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProvider;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Pair;
+import android.view.View;
+import android.widget.RemoteViews;
+
+import com.android.cts.verifier.R;
+
+/**
+ * The weather widget's AppWidgetProvider.
+ */
+public class WidgetCtsProvider extends AppWidgetProvider {
+ class TextData {
+ String title;
+ String instruction;
+ String dataP;
+ String dataL;
+
+ public TextData(String t, String i, String dp, String dl) {
+ title = t;
+ instruction = i;
+ dataL = dl;
+ dataP = dp;
+ }
+ }
+
+ public static String PASS = "com.example.android.widgetcts.PASS";
+ public static String FAIL = "com.example.android.widgetcts.FAIL";
+
+ public static final int STATE_BEGIN = 0;
+ public static final int STATE_VERIFY_SIZE_CALLBACK = 1;
+ public static final int STATE_VERIFY_RESIZE = 2;
+ public static final int STATE_VERIFY_COLLECTIONS = 3;
+ public static final int STATE_VERIFY_HOME_OR_KEYGUARD_CALLBACK = 4;
+ public static final int STATE_COMPLETE = 5;
+
+ // If relevant, we want to verify the size callback first, before any
+ // resizing.
+ static HashMap<Integer, Integer> sStateMap = new HashMap<Integer, Integer>();
+ static HashMap<Integer, Integer> sTestCount = new HashMap<Integer, Integer>();
+ static HashMap<Integer, Integer> sPassCount = new HashMap<Integer, Integer>();
+
+ private static int sSDKLevel = android.os.Build.VERSION.SDK_INT;
+
+ public WidgetCtsProvider() {
+ }
+
+ @Override
+ public void onReceive(Context ctx, Intent intent) {
+ final String action = intent.getAction();
+ if (action.equals(PASS) || action.equals(FAIL)) {
+ boolean pass = action.equals(PASS);
+
+ int widgetId = (Integer) intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
+ -1);
+
+ if (sStateMap.get(widgetId) != STATE_BEGIN && sStateMap.get(widgetId)
+ != STATE_COMPLETE) {
+ if (!sTestCount.containsKey(widgetId)) {
+ sTestCount.put(widgetId, 0);
+ }
+ if (!sPassCount.containsKey(widgetId)) {
+ sPassCount.put(widgetId, 0);
+ }
+
+ sPassCount.put(widgetId, sPassCount.get(widgetId) + (pass ? 1 : 0));
+ sTestCount.put(widgetId, sTestCount.get(widgetId) + 1);
+ }
+ gotoNextTest(widgetId);
+
+ AppWidgetManager mgr = AppWidgetManager.getInstance(ctx);
+ Bundle options = getAppWidgetOptions(mgr, widgetId);
+ updateWidget(ctx, widgetId, mgr, options);
+ }
+ super.onReceive(ctx, intent);
+ }
+
+ @Override
+ public void onDeleted(Context ctx, int[] ids) {
+ for (int i = 0; i < ids.length; i++) {
+ sStateMap.remove(ids[i]);
+ }
+ }
+
+ Bundle getAppWidgetOptions(AppWidgetManager mgr, int widgetId) {
+ if (sSDKLevel >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
+ return mgr.getAppWidgetOptions(widgetId);
+ }
+ return null;
+ }
+
+ void gotoNextTest(int widgetId) {
+ int state = sStateMap.get(widgetId);
+ boolean foundNextTest = false;
+ do {
+ state = state == STATE_COMPLETE ? state : state + 1;
+ foundNextTest = shouldPerformTest(state);
+ } while (state < STATE_COMPLETE && !foundNextTest);
+ sStateMap.put(widgetId, state);
+ }
+
+ private boolean shouldPerformTest(int state) {
+ if (state == STATE_VERIFY_SIZE_CALLBACK
+ && sSDKLevel < android.os.Build.VERSION_CODES.JELLY_BEAN) {
+ return false;
+ } else if (state == STATE_VERIFY_RESIZE
+ && sSDKLevel < android.os.Build.VERSION_CODES.HONEYCOMB) {
+ return false;
+ } else if (state == STATE_VERIFY_COLLECTIONS
+ && sSDKLevel < android.os.Build.VERSION_CODES.HONEYCOMB) {
+ return false;
+ } else if (state == STATE_VERIFY_HOME_OR_KEYGUARD_CALLBACK
+ && sSDKLevel < android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
+ for (int i = 0; i < appWidgetIds.length; i++) {
+ int id = appWidgetIds[i];
+ if (!sStateMap.containsKey(id)) {
+ sStateMap.put(id, STATE_BEGIN);
+ }
+ updateWidget(context, appWidgetIds[i], appWidgetManager, null);
+ }
+ }
+
+ @Override
+ public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager,
+ int appWidgetId, Bundle newOptions) {
+ updateWidget(context, appWidgetId, appWidgetManager, newOptions);
+ }
+
+ private TextData getInstruction(int state, Bundle options, int widgetId) {
+ String title = null;
+ String instruction = null;
+ String dataL = null;
+ String dataP = null;
+
+ int widthP = -1;
+ int heightP = -1;
+ int widthL = -1;
+ int heightL = -1;
+ int category = -1;
+
+ // We use nullness of options as a proxy for an sdk check >= JB
+ if (options != null) {
+ widthP = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, -1);
+ heightP = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, -1);
+ widthL = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, -1);
+ heightL = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, -1);
+ category = options.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1);
+ }
+
+ int step = 1;
+ if (sTestCount.containsKey(widgetId)) {
+ step = sTestCount.get(widgetId) + 1;
+ }
+ if (state == STATE_BEGIN) {
+ instruction = "This is a test of the widget framework";
+ } else if (state == STATE_VERIFY_SIZE_CALLBACK) {
+ title = "Step " + step + ": Verify dimensions";
+ instruction = "Verify that the width and height indicated below constitute reasonable"
+ + " approximations of the widget's actual size:";
+ dataP = "Width: " + widthP + " Height: " + heightP;
+ dataL = "Width: " + widthL + " Height: " + heightL;
+ } else if (state == STATE_VERIFY_RESIZE) {
+ title = "Step " + step + ": Verify resizeability";
+ instruction = "Verify that there is a functional affordance which allows this widget"
+ + " to be resized. For example, when picked up and dropped, there may be a "
+ + " frame with handles. (This is not a requirement for widgets hosted on "
+ + " a tablet keyguard).";
+ if (sSDKLevel >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
+ instruction = instruction
+ + " Also, verify that after resize, the width and height below "
+ + "are updated accordingly.";
+ dataP = "Width: " + widthP + " Height: " + heightP;
+ dataL = "Width: " + widthL + " Height: " + heightL;
+ }
+ } else if (state == STATE_VERIFY_COLLECTIONS) {
+ title = "Step " + step + ": Verify collections";
+ instruction = "Verify that the widget contains a scrollable list of numbers from 1"
+ + " to " + WidgetCtsService.NUM_ITEMS;
+ } else if (state == STATE_VERIFY_HOME_OR_KEYGUARD_CALLBACK) {
+ title = "Step " + step + ": Verify category";
+ instruction = "Verify that the text below accurately reflects whether this widget is"
+ + " on the home screen or the lock screen. ";
+ if (category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) {
+ dataL = dataP = "Widget is reportedly on: KEYGUARD";
+ } else if (category == AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN) {
+ dataL = dataP = "Widget is reportedly on: HOME SCREEN";
+ } else {
+ dataL = dataP = "Error.";
+ }
+ } else if (state == STATE_COMPLETE) {
+ title = "Test Complete";
+ instruction = "This completes the test of the widget framework. " +
+ "Remove and re-add this widget to restart the test.";
+ dataL = dataP = sPassCount.get(widgetId) + " of " + sTestCount.get(widgetId)
+ + " tests passed successfully.";
+ }
+ return new TextData(title, instruction, dataP, dataL);
+ }
+
+ private void updateWidget(Context context, int appWidgetId, AppWidgetManager appWidgetManager,
+ Bundle newOptions) {
+ // Pull them from the manager
+ if (newOptions == null) {
+ newOptions = getAppWidgetOptions(appWidgetManager, appWidgetId);
+ }
+
+ int baseLayout = R.layout.widget_layout;
+
+ RemoteViews rv = new RemoteViews(context.getPackageName(), baseLayout);
+ int state = sStateMap.get(appWidgetId);
+
+ TextData text = getInstruction(state, newOptions, appWidgetId);
+ rv.setTextViewText(R.id.instruction, text.instruction);
+
+ // Update the title
+ if (text.title != null) {
+ rv.setTextViewText(R.id.title, text.title);
+ }
+
+ if (state == STATE_VERIFY_COLLECTIONS) {
+ // Specify the service to provide data for the collection widget.
+ // Note that we need to
+ // embed the appWidgetId via the data otherwise it will be ignored.
+ final Intent intent = new Intent(context, WidgetCtsService.class);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
+ rv.setViewVisibility(R.id.list, View.VISIBLE);
+ rv.setRemoteAdapter(appWidgetId, R.id.list, intent);
+ } else {
+ rv.setViewVisibility(R.id.list, View.GONE);
+ }
+
+ if (state == STATE_BEGIN) {
+ rv.setViewVisibility(R.id.fail, View.GONE);
+ rv.setTextViewText(R.id.pass, "Start Test");
+ } else if (state == STATE_COMPLETE) {
+ rv.setViewVisibility(R.id.fail, View.GONE);
+ rv.setViewVisibility(R.id.pass, View.GONE);
+ } else {
+ rv.setViewVisibility(R.id.fail, View.VISIBLE);
+ rv.setTextViewText(R.id.pass, "Pass");
+ }
+
+ final Intent pass = new Intent(context, WidgetCtsProvider.class);
+ pass.setAction(WidgetCtsProvider.PASS);
+ pass.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ pass.setData(Uri.parse(pass.toUri(Intent.URI_INTENT_SCHEME)));
+ final PendingIntent passPendingIntent = PendingIntent.getBroadcast(context, 0, pass,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ final Intent fail = new Intent(context, WidgetCtsProvider.class);
+ fail.setAction(WidgetCtsProvider.FAIL);
+ fail.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ fail.setData(Uri.parse(fail.toUri(Intent.URI_INTENT_SCHEME)));
+ final PendingIntent failPendingIntent = PendingIntent.getBroadcast(context, 0, fail,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ rv.setOnClickPendingIntent(R.id.pass, passPendingIntent);
+ rv.setOnClickPendingIntent(R.id.fail, failPendingIntent);
+
+ RemoteViews rvL = null;
+ if (text.dataP != null && !text.dataP.equals(text.dataL)) {
+ rvL = rv.clone();
+
+ System.out.println("hmmmm ok, made it innnnn");
+ if (text.dataL != null) {
+ rvL.setViewVisibility(R.id.data, View.VISIBLE);
+ rvL.setTextViewText(R.id.data, text.dataL);
+ } else {
+ rvL.setViewVisibility(R.id.data, View.GONE);
+ }
+ }
+
+ // Update the data
+ if (text.dataP != null) {
+ rv.setViewVisibility(R.id.data, View.VISIBLE);
+ rv.setTextViewText(R.id.data, text.dataP);
+ } else {
+ rv.setViewVisibility(R.id.data, View.GONE);
+ }
+
+ RemoteViews rvFinal = rv;
+ if (rvL != null) {
+ rvFinal = new RemoteViews(rvL, rv);
+ }
+
+ appWidgetManager.updateAppWidget(appWidgetId, rvFinal);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetCtsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetCtsService.java
new file mode 100644
index 0000000..7d210a2
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetCtsService.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2013 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.cts.verifier.widget;
+
+import android.content.Context;
+import android.content.Intent;
+import android.widget.RemoteViews;
+import android.widget.RemoteViewsService;
+
+import com.android.cts.verifier.R;
+
+/**
+ * This is the service that provides the factory to be bound to the collection
+ * service.
+ */
+public class WidgetCtsService extends RemoteViewsService {
+ public static final int NUM_ITEMS = 50;
+
+ @Override
+ public RemoteViewsFactory onGetViewFactory(Intent intent) {
+ return new CtsRemoteViewsFactory(this.getApplicationContext(), intent);
+ }
+}
+
+/**
+ * This is the factory that will provide data to the collection widget.
+ */
+class CtsRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
+
+ Context mContext;
+
+ public CtsRemoteViewsFactory(Context context, Intent intent) {
+ mContext = context;
+ }
+
+ public void onCreate() {
+ }
+
+ public void onDestroy() {
+ }
+
+ public int getCount() {
+ return WidgetCtsService.NUM_ITEMS;
+ }
+
+ public RemoteViews getViewAt(int position) {
+ RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.list_item);
+ String text = "List Item " + (position + 1);
+ rv.setTextViewText(R.id.list_item_text, text);
+ return rv;
+ }
+
+ public RemoteViews getLoadingView() {
+ // We aren't going to return a default loading view in this sample
+ return null;
+ }
+
+ public int getViewTypeCount() {
+ // Technically, we have two types of views (the dark and light
+ // background views)
+ return 1;
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ public void onDataSetChanged() {
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetTestActivity.java
new file mode 100644
index 0000000..25f0a7a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetTestActivity.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013 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.cts.verifier.widget;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+
+/**
+ * CTS Verifier case for verifying basic widget framework functionality.
+ */
+public class WidgetTestActivity extends PassFailButtons.Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.pass_fail_widget);
+ setPassFailButtonClickListeners();
+ setInfoResources(R.string.widget_framework_test, R.string.widget_framework_test_info, -1);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+}