Skip to content

Instantly share code, notes, and snippets.

@HRankit
Last active August 4, 2018 06:04
Show Gist options
  • Save HRankit/d9df12912d2d25a0ec1908faf64743e7 to your computer and use it in GitHub Desktop.
Save HRankit/d9df12912d2d25a0ec1908faf64743e7 to your computer and use it in GitHub Desktop.
This is gist for creating a widget. Let me know if something is missing. The Widget has a gridview which shows an image and text below it. It is set to show only one item per column.
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="180dp"
android:minHeight="180dp"
android:updatePeriodMillis="10000"
android:previewImage="@drawable/ic_tablespoon"
android:initialLayout="@layout/widget_layout"
android:resizeMode="horizontal|vertical"
>
</appwidget-provider>
package com.udacity.baketime.baketime.widget;
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;
import com.udacity.baketime.baketime.MainActivity;
import com.udacity.baketime.baketime.R;
import static com.udacity.baketime.baketime.misc.MiscFunctions.ACTION_FROM_WIDGET;
import static com.udacity.baketime.baketime.misc.MiscFunctions.INTENT_FROM_WIDGET;
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();
startMainActivity(context, viewIndex);
}
super.onReceive(context, intent);
}
public void startMainActivity(Context context, int positions) {
Intent toastIntent = new Intent(context, MainActivity.class);
toastIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
toastIntent.setAction(ACTION_FROM_WIDGET);
toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, positions);
toastIntent.putExtra(INTENT_FROM_WIDGET, positions);
context.startActivity(toastIntent);
}
@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.gridView1, 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.gridView1, 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.gridView1, toastPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
}
package com.udacity.baketime.baketime.widget;
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;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.udacity.baketime.baketime.R;
import com.udacity.baketime.baketime.misc.MyPreferences;
import static com.udacity.baketime.baketime.misc.MiscFunctions.EXTRA_WIDGET_DATA;
import static com.udacity.baketime.baketime.misc.MiscFunctions.MAIN_ACTIVITY;
import static com.udacity.baketime.baketime.misc.MiscFunctions.NUMBER_OF_STEPS;
import static com.udacity.baketime.baketime.misc.MiscFunctions.WHICH_ACTIVITY;
import static com.udacity.baketime.baketime.misc.MiscFunctions.isEmpty;
public class StackWidgetService extends RemoteViewsService {
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
}
}
class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private int mStepsCount;
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.
MyPreferences yourPrefrence = MyPreferences.getInstance(mContext);
mStepsCount = yourPrefrence.getDataInt(NUMBER_OF_STEPS);
if (yourPrefrence.getDataInt(WHICH_ACTIVITY) == MAIN_ACTIVITY){
Gson gson = new Gson();
java.lang.reflect.Type type = new TypeToken<List<String>>() {}.getType();
String json = yourPrefrence.getData(EXTRA_WIDGET_DATA);
if (!isEmpty(json)){
List<String> arrayList = gson.fromJson(json, type);
for (int i = 0; i < mStepsCount; i++) {
mWidgetItems.add(new WidgetItem(arrayList.get(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 mStepsCount;
}
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_text, 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);
rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent);
rv.setOnClickFillInIntent(R.id.widget_image, 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.
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/widget_image"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:src="@mipmap/ic_launcher_foreground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/widget_item"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget_item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:autoSizeMaxTextSize="50dp"
android:autoSizeMinTextSize="20dp"
android:autoSizeStepGranularity="2dp"
android:gravity="center"
android:layout_gravity="center_horizontal"
android:padding="2dp"
android:text="Hello World"
android:textColor="@color/anothercolorText"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget_item_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/widgetBackgroundColor"
android:orientation="vertical">
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="10dp"
android:gravity="center_horizontal"
android:paddingBottom="15dp"
android:text="@string/recipe_s_available"
android:textColor="#ffffff"
android:textSize="20sp"
android:fontFamily="serif-monospace"
android:textStyle="bold" />
<GridView
android:id="@+id/gridView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:numColumns="1" />
<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:layout_gravity="center"
android:gravity="center"
android:text="@string/time_to_bake"
android:textColor="#ffffff"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
package com.udacity.baketime.baketime.widget;
public class WidgetItem {
public String text;
public WidgetItem(String text) {
this.text = text;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment