diff --git a/samples/HoneycombGallery/AndroidManifest.xml b/samples/HoneycombGallery/AndroidManifest.xml index 60fd4c62fc1..6e6163bf0e0 100644 --- a/samples/HoneycombGallery/AndroidManifest.xml +++ b/samples/HoneycombGallery/AndroidManifest.xml @@ -47,19 +47,5 @@ - - - - - - - - - - diff --git a/samples/HoneycombGallery/_index.html b/samples/HoneycombGallery/_index.html index 963661e988e..5566fb5d29d 100644 --- a/samples/HoneycombGallery/_index.html +++ b/samples/HoneycombGallery/_index.html @@ -9,8 +9,8 @@
  • The new android.animation framework
  • Custom notifications
  • -
  • StackView - and other adapter-based app widgets
  • +
  • For information on how to implement StackView + and other adapter-based app widgets, see StackView App Widget
  • The image gallery shows how all these pieces can work together in one application.

    diff --git a/samples/HoneycombGallery/res/drawable-nodpi/widget_preview.png b/samples/HoneycombGallery/res/drawable-nodpi/widget_preview.png deleted file mode 100644 index b2a13427847..00000000000 Binary files a/samples/HoneycombGallery/res/drawable-nodpi/widget_preview.png and /dev/null differ diff --git a/samples/HoneycombGallery/res/drawable/widget_item_background.xml b/samples/HoneycombGallery/res/drawable/widget_item_background.xml deleted file mode 100644 index aad4da35e2b..00000000000 --- a/samples/HoneycombGallery/res/drawable/widget_item_background.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - diff --git a/samples/HoneycombGallery/res/layout/widget_item.xml b/samples/HoneycombGallery/res/layout/widget_item.xml deleted file mode 100644 index a1cbe1f83c5..00000000000 --- a/samples/HoneycombGallery/res/layout/widget_item.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - diff --git a/samples/HoneycombGallery/res/xml/widget_info.xml b/samples/HoneycombGallery/res/xml/widget_info.xml deleted file mode 100644 index db95f9c31df..00000000000 --- a/samples/HoneycombGallery/res/xml/widget_info.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/samples/HoneycombGallery/src/com/example/android/hcgallery/widget/WidgetService.java b/samples/HoneycombGallery/src/com/example/android/hcgallery/widget/WidgetService.java deleted file mode 100644 index e7aaa6b3726..00000000000 --- a/samples/HoneycombGallery/src/com/example/android/hcgallery/widget/WidgetService.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2007 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.example.android.hcgallery.widget; - -import com.example.android.hcgallery.R; - -import java.util.ArrayList; -import java.util.List; -import android.appwidget.AppWidgetManager; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.util.Log; -import android.widget.RemoteViews; -import android.widget.RemoteViewsService; - -public class WidgetService extends RemoteViewsService { - - private class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { - private static final int mCount = 10; - private List mWidgetItems = new ArrayList(); - private Context mContext; - private int mAppWidgetId; - - public StackRemoteViewsFactory(Context context, Intent intent) { - mContext = context; - mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, - AppWidgetManager.INVALID_APPWIDGET_ID); - } - - public void onCreate() { - // In onCreate() you setup any connections / cursors to your data source. Heavy lifting, - // for example downloading or creating content etc, should be deferred to getViewAt() or - // onDataSetChanged(). Taking more than 20 seconds in this call will result in an ANR. - for (int i = 0; i < mCount; i++) { - mWidgetItems.add(new WidgetItem(i + "!")); - } - - // We sleep for 3 seconds here to show how the empty view appears in the interim. - // The empty view is set in the WidgetProvider and should be a sibling of the - // collection view. - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - public void onDestroy() { - // In onDestroy() you should tear down anything that was setup for your data source, - // eg. cursors, connections, etc. - mWidgetItems.clear(); - } - - public int getCount() { - return mCount; - } - - public RemoteViews getViewAt(int position) { - // position will always range from 0 to getCount() - 1. - - // We construct a remote views item based on our widget item xml file, and set the - // text based on the position. - RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item); - rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text); - - // Next, we set an intent so that clicking on this view will result in a toast message - Bundle extras = new Bundle(); - extras.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); - extras.putInt("numberToToast", position); - Intent fillInIntent = new Intent(); - fillInIntent.putExtras(extras); - rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent); - - // You can do heaving lifting in here, synchronously. For example, if you need to - // process an image, fetch something from the network, etc., it is ok to do it here, - // synchronously. A loading view will show up in lieu of the actual contents in the - // interim. - try { - Log.d("WidgetService/getViewAt", "Loading view " + position); - // Simulating a time-consuming operation. NO NEED to include this call in your app! - Thread.sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - // Return our remote views object. - return rv; - } - - public RemoteViews getLoadingView() { - // You can create a custom loading view (for instance when getViewAt() is slow. If you - // return null here, you will get the default loading view. - return null; - } - - public int getViewTypeCount() { - return 1; - } - - public long getItemId(int position) { - return position; - } - - public boolean hasStableIds() { - return true; - } - - public void onDataSetChanged() { - // This is triggered when you call AppWidgetManager notifyAppWidgetViewDataChanged - // on the collection view corresponding to this factory. You can do heaving lifting in - // here, synchronously. For example, if you need to process an image, fetch something - // from the network, etc., it is ok to do it here, synchronously. The widget will remain - // in its current state while work is being done here, so you don't need to worry about - // locking up the widget. - } - } - - public RemoteViewsFactory onGetViewFactory(Intent intent) { - return new StackRemoteViewsFactory(this.getApplicationContext(), intent); - } -} diff --git a/samples/StackWidget/Android.mk b/samples/StackWidget/Android.mk new file mode 100644 index 00000000000..016a454eafb --- /dev/null +++ b/samples/StackWidget/Android.mk @@ -0,0 +1,16 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +# Only compile source java files in this apk. +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := StackWidget + +LOCAL_SDK_VERSION := current + +include $(BUILD_PACKAGE) + +# Use the following include to make our test apk. +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/samples/StackWidget/AndroidManifest.xml b/samples/StackWidget/AndroidManifest.xml new file mode 100644 index 00000000000..1fec1570e6c --- /dev/null +++ b/samples/StackWidget/AndroidManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/StackWidget/_index.html b/samples/StackWidget/_index.html new file mode 100644 index 00000000000..e1af3179a3a --- /dev/null +++ b/samples/StackWidget/_index.html @@ -0,0 +1,31 @@ +

    + This sample shows how to construct a simple collection widget. This particular example shows how + to create a widget containing a StackView + ; however, only minimal changes are required to include + a ListView, + GridView or + AdapterViewFlipper instead. +

    +

    + The sample demonstrates the following: +

    +
      +
    • + The pattern for creating and wiring a RemoteViewsService + and RemoteViewsFactory which + serve the function of an adapter for the widget collection. +
    • +
    • + The pattern for setting an intent template and fill-in intents in order to + provide children of the collection with click behaviour. +
    • +
    • + How to make a widget with a StackView + (or AdapterViewFlipper) auto-advance. +
    • +
    • + How to set a widget preview image. +
    • +
    +The widget. \ No newline at end of file diff --git a/samples/StackWidget/res/drawable-hdpi/icon.png b/samples/StackWidget/res/drawable-hdpi/icon.png new file mode 100644 index 00000000000..8074c4c571b Binary files /dev/null and b/samples/StackWidget/res/drawable-hdpi/icon.png differ diff --git a/samples/StackWidget/res/drawable-ldpi/icon.png b/samples/StackWidget/res/drawable-ldpi/icon.png new file mode 100644 index 00000000000..1095584ec21 Binary files /dev/null and b/samples/StackWidget/res/drawable-ldpi/icon.png differ diff --git a/samples/StackWidget/res/drawable-mdpi/icon.png b/samples/StackWidget/res/drawable-mdpi/icon.png new file mode 100644 index 00000000000..a07c69fa5a0 Binary files /dev/null and b/samples/StackWidget/res/drawable-mdpi/icon.png differ diff --git a/samples/StackWidget/res/drawable-nodpi/preview.png b/samples/StackWidget/res/drawable-nodpi/preview.png new file mode 100644 index 00000000000..f2f83a0adcb Binary files /dev/null and b/samples/StackWidget/res/drawable-nodpi/preview.png differ diff --git a/samples/StackWidget/res/drawable-nodpi/widget_item_background.xml b/samples/StackWidget/res/drawable-nodpi/widget_item_background.xml new file mode 100644 index 00000000000..c0b3843e8c4 --- /dev/null +++ b/samples/StackWidget/res/drawable-nodpi/widget_item_background.xml @@ -0,0 +1,18 @@ + + + + + diff --git a/samples/StackWidget/res/layout/widget_item.xml b/samples/StackWidget/res/layout/widget_item.xml new file mode 100644 index 00000000000..75e31ab51f0 --- /dev/null +++ b/samples/StackWidget/res/layout/widget_item.xml @@ -0,0 +1,24 @@ + + + diff --git a/samples/HoneycombGallery/res/layout/widget_layout.xml b/samples/StackWidget/res/layout/widget_layout.xml similarity index 56% rename from samples/HoneycombGallery/res/layout/widget_layout.xml rename to samples/StackWidget/res/layout/widget_layout.xml index 987465086fe..11f9d3665ef 100644 --- a/samples/HoneycombGallery/res/layout/widget_layout.xml +++ b/samples/StackWidget/res/layout/widget_layout.xml @@ -1,19 +1,18 @@ - + 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. +--> @@ -31,6 +30,6 @@ android:background="@drawable/widget_item_background" android:textColor="#ffffff" android:textStyle="bold" - android:text="@string/widget_empty_view_text" + android:text="@string/empty_view_text" android:textSize="20sp" /> diff --git a/samples/StackWidget/res/values/strings.xml b/samples/StackWidget/res/values/strings.xml new file mode 100644 index 00000000000..acb2f7feee7 --- /dev/null +++ b/samples/StackWidget/res/values/strings.xml @@ -0,0 +1,18 @@ + + + + This is the empty view + diff --git a/samples/StackWidget/res/xml/stackwidgetinfo.xml b/samples/StackWidget/res/xml/stackwidgetinfo.xml new file mode 100644 index 00000000000..8c2630f5389 --- /dev/null +++ b/samples/StackWidget/res/xml/stackwidgetinfo.xml @@ -0,0 +1,24 @@ + + + + \ No newline at end of file diff --git a/samples/HoneycombGallery/src/com/example/android/hcgallery/widget/WidgetProvider.java b/samples/StackWidget/src/com/example/android/stackwidget/StackWidgetProvider.java similarity index 83% rename from samples/HoneycombGallery/src/com/example/android/hcgallery/widget/WidgetProvider.java rename to samples/StackWidget/src/com/example/android/stackwidget/StackWidgetProvider.java index 07a984d14a9..e053c210334 100644 --- a/samples/HoneycombGallery/src/com/example/android/hcgallery/widget/WidgetProvider.java +++ b/samples/StackWidget/src/com/example/android/stackwidget/StackWidgetProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 The Android Open Source Project + * 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. @@ -14,9 +14,7 @@ * limitations under the License. */ -package com.example.android.hcgallery.widget; - -import com.example.android.hcgallery.R; +package com.example.android.stackwidget; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; @@ -27,8 +25,9 @@ import android.widget.RemoteViews; import android.widget.Toast; -public class WidgetProvider extends AppWidgetProvider { - public static String TOAST_ACTION = "com.example.android.widget.action.TOAST"; +public class StackWidgetProvider extends AppWidgetProvider { + public static final String TOAST_ACTION = "com.example.android.stackwidget.TOAST_ACTION"; + public static final String EXTRA_ITEM = "com.example.android.stackwidget.EXTRA_ITEM"; @Override public void onDeleted(Context context, int[] appWidgetIds) { @@ -47,12 +46,11 @@ public void onEnabled(Context context) { @Override public void onReceive(Context context, Intent intent) { - AppWidgetManager mgr = AppWidgetManager.getInstance(context); if (intent.getAction().equals(TOAST_ACTION)) { int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); - int viewIndex = intent.getIntExtra("numberToToast", 0); + int viewIndex = intent.getIntExtra(EXTRA_ITEM, 0); Toast.makeText(context, "Touched view " + viewIndex, Toast.LENGTH_SHORT).show(); } super.onReceive(context, intent); @@ -65,7 +63,7 @@ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] a // Here we setup the intent which points to the StackViewService which will // provide the views for this collection. - Intent intent = new Intent(context, WidgetService.class); + Intent intent = new Intent(context, StackWidgetService.class); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); // When intents are compared, the extras are ignored, so we need to embed the extras // into the data so that the extras will not be ignored. @@ -81,10 +79,10 @@ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] a // cannot setup their own pending intents, instead, the collection as a whole can // setup a pending intent template, and the individual items can set a fillInIntent // to create unique before on an item to item basis. - Intent toastIntent = new Intent(context, WidgetProvider.class); - toastIntent.setAction(WidgetProvider.TOAST_ACTION); + Intent toastIntent = new Intent(context, StackWidgetProvider.class); + toastIntent.setAction(StackWidgetProvider.TOAST_ACTION); toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); - toastIntent.setData(Uri.parse("widgetid" + appWidgetIds[i])); + intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0, toastIntent, PendingIntent.FLAG_UPDATE_CURRENT); rv.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent); @@ -93,4 +91,4 @@ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] a } super.onUpdate(context, appWidgetManager, appWidgetIds); } -} +} \ No newline at end of file diff --git a/samples/StackWidget/src/com/example/android/stackwidget/StackWidgetService.java b/samples/StackWidget/src/com/example/android/stackwidget/StackWidgetService.java new file mode 100644 index 00000000000..d53b0ea5d1e --- /dev/null +++ b/samples/StackWidget/src/com/example/android/stackwidget/StackWidgetService.java @@ -0,0 +1,133 @@ +/* + * 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. + */ + +package com.example.android.stackwidget; + +import java.util.ArrayList; +import java.util.List; + +import android.appwidget.AppWidgetManager; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.widget.RemoteViews; +import android.widget.RemoteViewsService; + +public class StackWidgetService extends RemoteViewsService { + @Override + public RemoteViewsFactory onGetViewFactory(Intent intent) { + return new StackRemoteViewsFactory(this.getApplicationContext(), intent); + } +} + +class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { + private static final int mCount = 10; + private List mWidgetItems = new ArrayList(); + private Context mContext; + private int mAppWidgetId; + + public StackRemoteViewsFactory(Context context, Intent intent) { + mContext = context; + mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, + AppWidgetManager.INVALID_APPWIDGET_ID); + } + + public void onCreate() { + // In onCreate() you setup any connections / cursors to your data source. Heavy lifting, + // for example downloading or creating content etc, should be deferred to onDataSetChanged() + // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR. + for (int i = 0; i < mCount; i++) { + mWidgetItems.add(new WidgetItem(i + "!")); + } + + // We sleep for 3 seconds here to show how the empty view appears in the interim. + // The empty view is set in the StackWidgetProvider and should be a sibling of the + // collection view. + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public void onDestroy() { + // In onDestroy() you should tear down anything that was setup for your data source, + // eg. cursors, connections, etc. + mWidgetItems.clear(); + } + + public int getCount() { + return mCount; + } + + public RemoteViews getViewAt(int position) { + // position will always range from 0 to getCount() - 1. + + // We construct a remote views item based on our widget item xml file, and set the + // text based on the position. + RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item); + rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text); + + // Next, we set a fill-intent which will be used to fill-in the pending intent template + // which is set on the collection view in StackWidgetProvider. + Bundle extras = new Bundle(); + extras.putInt(StackWidgetProvider.EXTRA_ITEM, position); + Intent fillInIntent = new Intent(); + fillInIntent.putExtras(extras); + rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent); + + // You can do heaving lifting in here, synchronously. For example, if you need to + // process an image, fetch something from the network, etc., it is ok to do it here, + // synchronously. A loading view will show up in lieu of the actual contents in the + // interim. + try { + System.out.println("Loading view " + position); + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + // Return the remote views object. + return rv; + } + + public RemoteViews getLoadingView() { + // You can create a custom loading view (for instance when getViewAt() is slow.) If you + // return null here, you will get the default loading view. + return null; + } + + public int getViewTypeCount() { + return 1; + } + + public long getItemId(int position) { + return position; + } + + public boolean hasStableIds() { + return true; + } + + public void onDataSetChanged() { + // This is triggered when you call AppWidgetManager notifyAppWidgetViewDataChanged + // on the collection view corresponding to this factory. You can do heaving lifting in + // here, synchronously. For example, if you need to process an image, fetch something + // from the network, etc., it is ok to do it here, synchronously. The widget will remain + // in its current state while work is being done here, so you don't need to worry about + // locking up the widget. + } +} \ No newline at end of file diff --git a/samples/HoneycombGallery/src/com/example/android/hcgallery/widget/WidgetItem.java b/samples/StackWidget/src/com/example/android/stackwidget/WidgetItem.java similarity index 94% rename from samples/HoneycombGallery/src/com/example/android/hcgallery/widget/WidgetItem.java rename to samples/StackWidget/src/com/example/android/stackwidget/WidgetItem.java index 4c4b230d1e4..aa822ca3309 100644 --- a/samples/HoneycombGallery/src/com/example/android/hcgallery/widget/WidgetItem.java +++ b/samples/StackWidget/src/com/example/android/stackwidget/WidgetItem.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.example.android.hcgallery.widget; +package com.example.android.stackwidget; public class WidgetItem { public String text;