title: Android: Create colored TextClock widget
body: <p>I have been trying to make an Android widget that is simply a TextClock with a user-defined color.  However, after a restart of the launcher, the color of the TextClock always reverts to white and does not retain the user-defined color.  This is my first time making an Android widget, and I have been pulling my hair out for days trying to figure out why this is happening.</p>
  
  <p>So,</p>
  
  <p>the configuration activity:</p>
  
  <pre><code>public class MainActivity extends Activity {
  int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;;
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setResult(RESULT_CANCELED);
      setContentView(R.layout.main_activity);
  
      Intent intent = getIntent();
      Bundle extras = intent.getExtras();
      if (extras != null) {
          mAppWidgetId = extras.getInt(
                  AppWidgetManager.EXTRA_APPWIDGET_ID, 
                  AppWidgetManager.INVALID_APPWIDGET_ID);
      }
      // If they gave us an intent without the widget id, just bail.
      if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
          finish();
      }
  
      OnCancelListener cancelListener = new OnCancelListener()
      {
          @Override
          public void onCancel(DialogInterface dialog)
          {
               MainActivity.this.finish();
          }
      };
  
      OnColorChangedListener ccListener = new ColorPickerDialog.OnColorChangedListener(){
  
          @Override
          public void onColorChanged(int color) {
              PreferenceManager.getDefaultSharedPreferences(MainActivity.this).edit().putInt("color", color).apply();
              getSharedPreferences("" + mAppWidgetId, MODE_PRIVATE).edit().putInt("color", color).apply();
  
              AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(MainActivity.this);
              MyWidget.updateAppWidget(MainActivity.this, appWidgetManager, mAppWidgetId, color);
              Intent resultValue = new Intent();
              resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
              setResult(RESULT_OK, resultValue);
              finish();
          }
  
      };
  
      int initialColor = PreferenceManager.getDefaultSharedPreferences(this).getInt("color", Color.RED);
  
      ColorPickerDialog cpd = new ColorPickerDialog(this, initialColor);
      cpd.setHexValueEnabled(true);
      cpd.setAlphaSliderVisible(true);
      cpd.setOnColorChangedListener(ccListener);
      cpd.setOnCancelListener(cancelListener);
      cpd.show();
  
  
  }
  
  }
  </code></pre>
  
  <p>the AppWidgetProvider:</p>
  
  <pre><code>public class MyWidget extends AppWidgetProvider{
  
  @Override
  public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
      super.onUpdate(context, appWidgetManager, appWidgetIds);
      Log.d("Hey", "onUpdate");
      final int N = appWidgetIds.length;
      for (int i=0; i&lt;N; i++) {
          int appWidgetId = appWidgetIds[i];
          int color = context.getSharedPreferences("" + appWidgetId, Context.MODE_PRIVATE).getInt("color", Color.RED);
          updateAppWidget(context, appWidgetManager, appWidgetId, color);
      }
  }
  
  @Override
  public void onDeleted(Context context, int[] appWidgetIds) {
      super.onDeleted(context, appWidgetIds);
      // When the user deletes the widget, delete the preference associated with it.
      final int N = appWidgetIds.length;
      for (int i=0; i&lt;N; i++) {
          int appWidgetId = appWidgetIds[i];
          context.getSharedPreferences("" + appWidgetId, Context.MODE_PRIVATE).edit().clear().apply();
      }
  }
  
  @Override
  public void  onAppWidgetOptionsChanged (Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions){
      super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
      Log.d("updating", "updating");
      int nwidth = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH) - newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
      int nheight = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT) - newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
      Log.d("nheight", "" + nheight);
      Log.d("nwidth", "" + nwidth);
  
      RemoteViews views = new RemoteViews(context.getPackageName(),
              R.layout.activity_main);
  
      PackageManager packageManager = context.getPackageManager();
      Intent alarmClockIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER);
      // Verify clock implementation
      String clockImpls[][] = {
              {"HTC Alarm Clock", "com.htc.android.worldclock", "com.htc.android.worldclock.WorldClockTabControl" },
              {"Standard Alarm Clock", "com.android.deskclock", "com.android.deskclock.AlarmClock"},
              {"Froyo Nexus Alarm Clock", "com.google.android.deskclock", "com.android.deskclock.DeskClock"},
              {"Moto Blur Alarm Clock", "com.motorola.blur.alarmclock",  "com.motorola.blur.alarmclock.AlarmClock"},
              {"Samsung Galaxy Clock", "com.sec.android.app.clockpackage","com.sec.android.app.clockpackage.ClockPackage"}
      };
      boolean foundClockImpl = false;
      for(int i=0; i&lt;clockImpls.length; i++) {
          String vendor = clockImpls[i][0];
          String packageName = clockImpls[i][1];
          String className = clockImpls[i][2];
          try {
              ComponentName cn = new ComponentName(packageName, className);
              ActivityInfo aInfo = packageManager.getActivityInfo(cn, PackageManager.GET_META_DATA);
              alarmClockIntent.setComponent(cn);
              Log.d("Clock", "Found " + vendor + " --&gt; " + packageName + "/" + className + ".");
              foundClockImpl = true;
          } catch (NameNotFoundException e) {
              Log.d("Clock", vendor + " does not exists.");
          }
      }
      if (foundClockImpl) {
          PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, alarmClockIntent, 0);
              // add pending intent to your component
              // ....
          views.setOnClickPendingIntent(R.id.textClock, pendingIntent);
      }
  
      if (nwidth &gt;= 60 || nwidth==0){
          views.setTextViewTextSize(R.id.textClock, TypedValue.COMPLEX_UNIT_SP, 48);
      } else if(nwidth &gt;= 40){
          views.setTextViewTextSize(R.id.textClock, TypedValue.COMPLEX_UNIT_SP, 26);
      } else{
          views.setTextViewTextSize(R.id.textClock, TypedValue.COMPLEX_UNIT_SP, 12);
      }
      appWidgetManager.updateAppWidget(appWidgetId, views);
  }
  
  
  static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
          int appWidgetId, int color) {
  
      // Construct the RemoteViews object.  It takes the package name (in our case, it's our
      // package, but it needs this because on the other side it's the widget host inflating
      // the layout from our package).
      RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.activity_main);
      views.setTextColor(R.id.textClock, color);
  
      // Tell the widget manager
      appWidgetManager.updateAppWidget(appWidgetId, views);
  }
  
  }
  </code></pre>
  
  <p>activity_main.xml (the layout for the widget):</p>
  
  <pre><code>&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin" &gt;
  
  &lt;TextClock
      android:id="@+id/textClock"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:gravity="center"
  
      android:textSize="26sp"
  /&gt;
  
  &lt;/RelativeLayout&gt;
  </code></pre>
  
  <p>the appwidget_info.xml:</p>
  
  <pre><code>&lt;appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
  android:minWidth="80dp"
  android:minHeight="40dp"
  android:minResizeWidth="20dp"
  android:minResizeHeight="20dp"
  android:updatePeriodMillis="0"
  android:previewImage="@drawable/ic_launcher"
  android:initialLayout="@layout/activity_main"
  android:configure="com.brianco.colorclock.MainActivity"
  android:resizeMode="horizontal|vertical"
  android:widgetCategory="home_screen|keyguard"
  android:initialKeyguardLayout="@layout/activity_main"&gt;
  &lt;/appwidget-provider&gt;
  </code></pre>
  
  <p>...and in the AndroidManifest.xml:</p>
  
  <pre><code>&lt;application
      android:allowBackup="true"
      android:icon="@drawable/ic_launcher"
      android:label="@string/app_name" &gt;
      &lt;activity
          android:name="com.brianco.colorclock.MainActivity"
          android:label="@string/app_name"
          android:theme="@android:style/Theme.Translucent.NoTitleBar" &gt;
          &lt;intent-filter&gt;
              &lt;action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" /&gt;
          &lt;/intent-filter&gt;
      &lt;/activity&gt;
  
      &lt;receiver android:name="com.brianco.colorclock.MyWidget" &gt;
          &lt;intent-filter&gt;
              &lt;action android:name="android.appwidget.action.APPWIDGET_UPDATE" /&gt;
          &lt;/intent-filter&gt;
          &lt;meta-data android:name="android.appwidget.provider"
                  android:resource="@xml/appwidget_info" /&gt;
      &lt;/receiver&gt;
  &lt;/application&gt;
  </code></pre>
  
  <p>Any insight into why the settings from the configuration activity are not "sticking" would be greatly appreciated.  I hope to open-source this app if I ever solve this issue, so others can learn.</p>