Making StackWidget sample code stand alone as opposed to bundled with HoneycombGallery

Change-Id: I9da8433ee8a9710f5a5362a6f82fc96d4f456c88
diff --git a/samples/StackWidget/Android.mk b/samples/StackWidget/Android.mk
new file mode 100644
index 0000000..016a454
--- /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 0000000..1fec157
--- /dev/null
+++ b/samples/StackWidget/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?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.
+-->
+
+<!-- Declare the contents of this Android application.  The namespace
+     attribute brings in the Android platform namespace, and the package
+     supplies a unique name for the application.  When writing your
+     own application, the package name must be changed from "com.example.*"
+     to come from a domain that you own or have control over. -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.stackwidget">
+    <uses-sdk android:targetSdkVersion="11" android:minSdkVersion="11"/>
+    <application android:label="StackWidget">
+        <receiver android:name="StackWidgetProvider">
+            <intent-filter>
+                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+            </intent-filter>
+            <meta-data android:name="android.appwidget.provider"
+                android:resource="@xml/stackwidgetinfo" />
+        </receiver>
+
+        <service android:name="StackWidgetService"
+            android:permission="android.permission.BIND_REMOTEVIEWS"
+            android:exported="false" />
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/samples/StackWidget/_index.html b/samples/StackWidget/_index.html
new file mode 100644
index 0000000..e1af317
--- /dev/null
+++ b/samples/StackWidget/_index.html
@@ -0,0 +1,31 @@
+<p>
+    This sample shows how to construct a simple collection widget. This particular example shows how
+    to create a widget containing a <a href="../../../reference/android/widget/StackView.html"><code>StackView</code></a>
+    ; however, only minimal changes are required to include
+    a <a href="../../../reference/android/widget/ListView.html"><code>ListView</code></a>,
+    <a href="../../../reference/android/widget/GridView.html"><code>GridView</code></a> or
+    <a href="../../../reference/android/widget/AdapterViewFlipper.html"><code>AdapterViewFlipper</code></a> instead.
+</p>
+<p>
+    The sample demonstrates the following:
+</p>
+    <ul>
+        <li>
+            The pattern for creating and wiring a <a href="../../../reference/android/widget/RemoteViewsService.html"><code>RemoteViewsService</code></a>
+            and <a href="../../../reference/android/widget/RemoteViewsService.RemoteViewsFactory.html"><code>RemoteViewsFactory</code></a> which
+            serve the function of an adapter for the widget collection.
+        </li>
+        <li>
+            The pattern for setting an intent template and fill-in intents in order to
+            provide children of the collection with click behaviour.
+        </li>
+        <li>
+            How to make a widget with a <a href="../../../reference/android/widget/StackView.html"><code>StackView</code></a>
+            (or <a href="../../../reference/android/widget/AdapterViewFlipper.html"><code>AdapterViewFlipper</code></a>) auto-advance.
+        </li>
+        <li>
+            How to set a widget preview image.
+        </li>
+    </ul>
+<img alt="The widget."
+     src="../images/StackWidget.png"/>
\ 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 0000000..8074c4c
--- /dev/null
+++ b/samples/StackWidget/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/samples/StackWidget/res/drawable-ldpi/icon.png b/samples/StackWidget/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000..1095584
--- /dev/null
+++ b/samples/StackWidget/res/drawable-ldpi/icon.png
Binary files differ
diff --git a/samples/StackWidget/res/drawable-mdpi/icon.png b/samples/StackWidget/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/samples/StackWidget/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/samples/StackWidget/res/drawable-nodpi/preview.png b/samples/StackWidget/res/drawable-nodpi/preview.png
new file mode 100644
index 0000000..f2f83a0
--- /dev/null
+++ b/samples/StackWidget/res/drawable-nodpi/preview.png
Binary files 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 0000000..c0b3843
--- /dev/null
+++ b/samples/StackWidget/res/drawable-nodpi/widget_item_background.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+    <gradient android:startColor="#ff666666" android:endColor="#ff333333" android:angle="270" />
+</shape>
diff --git a/samples/StackWidget/res/layout/widget_item.xml b/samples/StackWidget/res/layout/widget_item.xml
new file mode 100644
index 0000000..75e31ab
--- /dev/null
+++ b/samples/StackWidget/res/layout/widget_item.xml
@@ -0,0 +1,24 @@
+<?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/widget_item"
+    android:layout_width="120dp"
+    android:layout_height="120dp"
+    android:gravity="center"
+    android:background="@drawable/widget_item_background"
+    android:textColor="#ffffff"
+    android:textStyle="bold"
+    android:textSize="44sp" />
diff --git a/samples/StackWidget/res/layout/widget_layout.xml b/samples/StackWidget/res/layout/widget_layout.xml
new file mode 100644
index 0000000..11f9d36
--- /dev/null
+++ b/samples/StackWidget/res/layout/widget_layout.xml
@@ -0,0 +1,35 @@
+<?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">
+    <StackView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/stack_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:loopViews="true" />
+    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/empty_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:background="@drawable/widget_item_background"
+        android:textColor="#ffffff"
+        android:textStyle="bold"
+        android:text="@string/empty_view_text"
+        android:textSize="20sp" />
+</FrameLayout>
diff --git a/samples/StackWidget/res/values/strings.xml b/samples/StackWidget/res/values/strings.xml
new file mode 100644
index 0000000..acb2f7f
--- /dev/null
+++ b/samples/StackWidget/res/values/strings.xml
@@ -0,0 +1,18 @@
+<?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>
+    <string name="empty_view_text">This is the empty view</string>
+</resources>
diff --git a/samples/StackWidget/res/xml/stackwidgetinfo.xml b/samples/StackWidget/res/xml/stackwidgetinfo.xml
new file mode 100644
index 0000000..8c2630f
--- /dev/null
+++ b/samples/StackWidget/res/xml/stackwidgetinfo.xml
@@ -0,0 +1,24 @@
+<?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="150dip"
+  android:minHeight="150dip"
+  android:updatePeriodMillis="3600000"
+  android:previewImage="@drawable/preview"
+  android:initialLayout="@layout/widget_layout"
+  android:autoAdvanceViewId="@id/stack_view">
+</appwidget-provider>
\ No newline at end of file
diff --git a/samples/StackWidget/src/com/example/android/stackwidget/StackWidgetProvider.java b/samples/StackWidget/src/com/example/android/stackwidget/StackWidgetProvider.java
new file mode 100644
index 0000000..e053c21
--- /dev/null
+++ b/samples/StackWidget/src/com/example/android/stackwidget/StackWidgetProvider.java
@@ -0,0 +1,94 @@
+/*
+ * 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 android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProvider;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.widget.RemoteViews;
+import android.widget.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) {
+        super.onDeleted(context, appWidgetIds);
+    }
+
+    @Override
+    public void onDisabled(Context context) {
+        super.onDisabled(context);
+    }
+
+    @Override
+    public void onEnabled(Context context) {
+        super.onEnabled(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(EXTRA_ITEM, 0);
+            Toast.makeText(context, "Touched view " + viewIndex, Toast.LENGTH_SHORT).show();
+        }
+        super.onReceive(context, intent);
+    }
+
+    @Override
+    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
+        // update each of the widgets with the remote adapter
+        for (int i = 0; i < appWidgetIds.length; ++i) {
+
+            // Here we setup the intent which points to the StackViewService which will
+            // provide the views for this collection.
+            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.
+            intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
+            RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
+            rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent);
+
+            // The empty view is displayed when the collection has no items. It should be a sibling
+            // of the collection view.
+            rv.setEmptyView(R.id.stack_view, R.id.empty_view);
+
+            // Here we setup the a pending intent template. Individuals items of a collection
+            // 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, StackWidgetProvider.class);
+            toastIntent.setAction(StackWidgetProvider.TOAST_ACTION);
+            toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 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);
+
+            appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
+        }
+        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 0000000..d53b0ea
--- /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<WidgetItem> mWidgetItems = new ArrayList<WidgetItem>();
+    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/StackWidget/src/com/example/android/stackwidget/WidgetItem.java b/samples/StackWidget/src/com/example/android/stackwidget/WidgetItem.java
new file mode 100644
index 0000000..aa822ca
--- /dev/null
+++ b/samples/StackWidget/src/com/example/android/stackwidget/WidgetItem.java
@@ -0,0 +1,25 @@
+/*
+ * 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;
+
+public class WidgetItem {
+    public String text;
+
+    public WidgetItem(String text) {
+        this.text = text;
+    }
+}