I have a problem to make a customizable AppWidget : I don't know how to do... I tried to update appearance regularly with this function :
public static void updateApparence(Context context)
{
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
for(int i = 0 ; i < widgetLayoutIds.length ; i++)
{
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, appWidgetProvidersClass[i]));
RemoteViews views = new RemoteViews(context.getPackageName(), widgetLayoutIds[i]);
views.setInt(R.id.widget_background, "setBackgroundColor", prefs.getInt(SettingsApparence.BACKGROUND_COLOR, 0xFFFFFFFF));
views.setInt(R.id.matiere, "setTextColor", prefs.getInt(SettingsApparence.COULEUR_MATIERE, 0xFF666666));
views.setInt(R.id.horaires, "setTextColor", prefs.getInt(SettingsApparence.COULEUR_HORAIRES, 0xFF888888));
views.setInt(R.id.salle, "setTextColor", prefs.getInt(SettingsApparence.COULEUR_SALLE, 0xFF888888));
Bitmap bm = BitmapFactory.decodeFile(context.getFilesDir() + PATH_CLE);
if(bm == null)
{
bm = BitmapFactory.decodeResource(context.getResources(), R.drawable.settings_icon);
bm = changeImageColor(bm, prefs.getInt(SettingsApparence.COULEUR_CLE, 0xFF000000));
}
views.setBitmap(R.id.settings, "setImageBitmap", bm);
bm = BitmapFactory.decodeFile(context.getFilesDir() + PATH_CALENDRIER);
if(bm == null)
{
bm = BitmapFactory.decodeResource(context.getResources(), R.drawable.calendrier_icon);
bm = changeImageColor(bm, prefs.getInt(SettingsApparence.COULEUR_CALENDRIER, 0xFF000000));
}
views.setBitmap(R.id.emploi_du_temps, "setImageBitmap", bm);
appWidgetManager.updateAppWidget(appWidgetIds, views);
}
}
But sometimes, the original appearance (in R.layout.widget, in appWidgetProvidersClass[]) reappear...
How can I do that ?
Related
the android widget content when device rotated are suddenly gone.
do I have to repopulate them when device is rotated? but the widget dont have onconfiguration change to listen to.
also I used alarmmanager with service to populate the widget for new app (adding to viewflipper) to display every 1 minute.
widget code:
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
try{
// create intent service per APP id
for(int i = 0; i < appWidgetIds.length; i++)
{
Log.e("onUpdate -- Widget_2_6", "onUpdate -- Widget_2_6: widget ID: " + appWidgetIds[i]);
// check if alarms not created, create 1
if(!GlobalStorage.tempStorage.containsKey(Widget_2_6.class.toString() + appWidgetIds[i]))
{
createAlarmService(context, appWidgetIds[i]);
// put to hash for alarms created
GlobalStorage.tempStorage.put(Widget_2_6.class.toString() + appWidgetIds[i], 0);
//CustomAndroidTools.popToast(Widget_2_6.class.toString() + appWidgetIds[i], context);
}
}
}
catch(Exception e)
{
Log.e("onUpdate -- Widget_2_6", "onUpdate -- Widget_2_6: error: " + e.toString());
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
private void createAlarmService(Context context, int id)
{
if(alarm == null)
{
createAlarm(context);
}
// each new alarm will repeat in increasing half minute: so first is 1 min next is 1 min and 30 sec ...
alarm.setRepeating(AlarmManager.RTC, 0, (1000 * (60 + (GlobalStorage.tempStorage.size() * 30))), createPendingIntent(context, id));
Log.e("createAlarmService -- Widget_2_6", "createAlarmService -- Widget_2_6, creating alarm for widget id: " + id);
}
service code:
if(CustomAndroidTools.checkDeviceIsInteractive(context))
{
new Thread(new Runnable() {
public void run() {
try{
ArrayList<AppInfo> appInfos = init(context, _class, widgetID);
buildUpdate(context, _class, widgetID, appInfos);
// update the limit offset here instead so that to ensure no exception came from building the UI of the widget
updateLimitOffset(_class, widgetID);
}
catch(Exception e)
{
Log.e("Thread -- onStartCommand -- WidgetUpdateService", "Thread -- onStartCommand -- WidgetUpdateService: error: " + e.toString());
}
}
}).start();
}
private ArrayList<AppInfo> init(Context context, Class<?> _class, int widgetID)
{
ArrayList<AppInfo> appInfos = new ArrayList<AppInfo>();
try{
appListManager alm = new appListManager(context);
int skip = 0;
//int limit = 10;
if(GlobalStorage.tempStorage.containsKey(_class.toString() + widgetID))
{
skip = GlobalStorage.tempStorage.get(_class.toString() + widgetID);
}
if(skip == 0) // first initialize
{
///TODO: for testing, get the first 5 used by banner
appInfos.add(alm.getAppById(30));
appInfos.add(alm.getAppById(16));
appInfos.add(alm.getAppById(13));
appInfos.add(alm.getAppById(12));
appInfos.add(alm.getAppById(6));
}
//appInfos = alm.getAllAppsUnderTheCategory(-1, skip, limit);
}
catch(Exception e)
{
Log.e("init -- WidgetUpdateService", "init -- WidgetUpdateService: error: " + e.toString());
}
return appInfos;
}
private void updateLimitOffset(Class<?> _class, int widgetID){
int skip = 0;
int limit = 10;
if(GlobalStorage.tempStorage.containsKey(_class.toString() + widgetID))
{
skip = GlobalStorage.tempStorage.get(_class.toString() + widgetID);
}
if(skip != 0)
{
limit = 5;
}
GlobalStorage.tempStorage.put(_class.toString() + widgetID, skip + limit); // update offset limit here
}
private void buildUpdate(Context context, Class<?> _class, int widgetID, ArrayList<AppInfo> appInfos) throws Exception
{
RemoteViews views = null;
appListManager alm = new appListManager(context);
try{
if(_class.equals(Widget_1_6.class) || _class.equals(Widget_1_6_2.class))
{
views = new RemoteViews(getPackageName(), R.layout.widget_1_6);
}
else if(_class.equals(Widget_2_6.class) || _class.equals(Widget_2_6_2.class))
{
views = new RemoteViews(getPackageName(), R.layout.widget_2_6);
}
if(alm.getTotalApps(-1) < 1)
{
views.setViewVisibility(R.id.app, View.GONE);
views.setViewVisibility(R.id.sorryText, View.VISIBLE);
views.setViewVisibility(R.id.loadingText, View.GONE);
}
else
{
views.setViewVisibility(R.id.app, View.VISIBLE);
views.setViewVisibility(R.id.sorryText, View.GONE);
views.setViewVisibility(R.id.loadingText, View.GONE);
if(appInfos != null)
{
for(int i = 0; i < appInfos.size(); i++)
{
views.addView(R.id.appInfo, inflateLayout(appInfos.get(i), context, _class, widgetID));
}
}
Intent refreshWidgetIncrement = new Intent(context, WidgetControlService.class);
refreshWidgetIncrement.putExtra(WidgetControlService.INCREMENT, true);
refreshWidgetIncrement.putExtra(WidgetControlService.DECREMENT, false);
refreshWidgetIncrement.putExtra(WidgetControlService.CLASS, _class);
refreshWidgetIncrement.putExtra(WidgetControlService.WIDGET_ID, widgetID);
refreshWidgetIncrement.setData(Uri.withAppendedPath(Uri.parse("BFR://widget/id/#togetituniqie" + WidgetControlService.class.toString()), UUID.randomUUID().toString()));
PendingIntent pIntentIncrement = PendingIntent.getService(context, 0, refreshWidgetIncrement, PendingIntent.FLAG_CANCEL_CURRENT);
views.setOnClickPendingIntent(R.id.arrowRight, pIntentIncrement);
Intent refreshWidgetDecrement = new Intent(context, WidgetControlService.class);
refreshWidgetDecrement.putExtra(WidgetControlService.DECREMENT, true);
refreshWidgetDecrement.putExtra(WidgetControlService.INCREMENT, false);
refreshWidgetDecrement.putExtra(WidgetControlService.CLASS, _class);
refreshWidgetDecrement.putExtra(WidgetControlService.WIDGET_ID, widgetID);
refreshWidgetDecrement.setData(Uri.withAppendedPath(Uri.parse("BFR://widget/id/#togetituniqie" + WidgetControlService.class.toString()), UUID.randomUUID().toString()));
PendingIntent pIntentDecrement = PendingIntent.getService(context, 0, refreshWidgetDecrement, PendingIntent.FLAG_CANCEL_CURRENT);
views.setOnClickPendingIntent(R.id.arrowLeft, pIntentDecrement);
}
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(widgetID, views);
}
catch(Exception e)
{
Log.e("buildUpdate -- WidgetUpdateService", "buildUpdate -- WidgetUpdateService: error: " + e.toString());
}
}
private RemoteViews inflateLayout(AppInfo appInfo, Context context, Class<?> _class, int widgetID) throws IOException
{
RemoteViews view = null;
if(_class.equals(Widget_1_6.class) || _class.equals(Widget_1_6_2.class))
{
view = new RemoteViews(getPackageName(), R.layout.widget_1_6_body_fragment);
view = inflateWidget1_6(view, appInfo, context, _class, widgetID);
}
else if(_class.equals(Widget_2_6.class) || _class.equals(Widget_2_6_2.class))
{
view = new RemoteViews(getPackageName(), R.layout.widget_2_6_body_fragment);
view = inflateWidget2_6(view, appInfo, context, _class, widgetID);
}
return view;
}
private RemoteViews inflateWidget1_6(RemoteViews view, AppInfo appInfo, Context context, Class<?> _class, int widgetID) throws IOException
{
view.setTextViewText(R.id.appTitle, appInfo.title);
view.setTextViewText(R.id.appDesc, appInfo.shortDesc);
File file = new File(Constants.saveImageLocation + appInfo.iconLoc);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
Bitmap bitmap = null;
if(file.exists()) // if exists in local
{
bitmap = BitmapFactory.decodeFile(Constants.saveImageLocation + appInfo.iconLoc, options);
}
else if (CustomAndroidTools.isImageFoundInAssets(appInfo.iconLoc, context))
{
bitmap = CustomAndroidTools.getImageFromAssets(appInfo.iconLoc, context);
}
else
{
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.broken, options);
}
view.setImageViewBitmap(R.id.appIcon, bitmap);
view.setOnClickPendingIntent(R.id.appIcon, null);
view.setOnClickPendingIntent(R.id.appDetail, null);
Intent openApp = new Intent(context, AppDetailViewActivity.class);
openApp.putExtra(AppDetailViewActivity.LAST_SELECTED_APP, appInfo);
Log.e("current App", "current App: name: " + appInfo.title + ", category index: " + appInfo.category + ". For Widget type: " + _class.toString() + ", id: " + widgetID);
openApp.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
openApp.setData(Uri.withAppendedPath(Uri.parse("BFR://widget/id/#togetituniqie" + new ComponentName(context, _class)), UUID.randomUUID().toString()));
PendingIntent pIntent = PendingIntent.getActivity(context, 0, openApp, 0);
view.setOnClickPendingIntent(R.id.appIcon, pIntent);
view.setOnClickPendingIntent(R.id.appDetail, pIntent);
return view;
}
private RemoteViews inflateWidget2_6(RemoteViews view, AppInfo appInfo, Context context, Class<?> _class, int widgetID) throws IOException
{
File file = new File(Constants.saveImageLocation + appInfo.bannerLoc);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
Bitmap bitmap = null;
if(file.exists()) // if exists in local
{
bitmap = BitmapFactory.decodeFile(Constants.saveImageLocation + appInfo.bannerLoc, options);
}
else if (CustomAndroidTools.isImageFoundInAssets(appInfo.bannerLoc, context))
{
bitmap = CustomAndroidTools.getImageFromAssets(appInfo.bannerLoc, context);
}
else
{
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.broken, options);
}
view.setImageViewBitmap(R.id.appBanner, bitmap);
view.setOnClickPendingIntent(R.id.appBanner, null);
Intent openApp = new Intent(context, AppDetailViewActivity.class);
openApp.putExtra(AppDetailViewActivity.LAST_SELECTED_APP, appInfo);
Log.e("current App", "current App: name: " + appInfo.title + ", category index: " + appInfo.category + ". For Widget type: " + _class.toString() + ", id: " + widgetID);
openApp.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
openApp.setData(Uri.withAppendedPath(Uri.parse("BFR://widget/id/#togetituniqie" + new ComponentName(context, _class)), UUID.randomUUID().toString()));
PendingIntent pIntent = PendingIntent.getActivity(context, 0, openApp, 0);
view.setOnClickPendingIntent(R.id.appBanner, pIntent);
return view;
}
is there anything i missed?
Ok. got it working, the problem is with the RemoteView's behavior.(NOTE: RemoteView will send the latest changes to views needing a refresh/update)
so what I did was instead of using manager.updateAppWidget(widgetID, views); on all occasion.
I used a flag to know when to use updateAppWidget or partiallyUpdateAppWidget.
below is the modified code under the buildUpdate function from above listing, replacing manager.updateAppWidget(widgetID, views); into:
if(!GlobalStorage.tempStorage.containsKey(_class.toString() + widgetID) || GlobalStorage.tempStorage.get(_class.toString() + widgetID) == 0)
{
Log.e("buildUpdate -- WidgetUpdateService", "buildUpdate -- WidgetUpdateService: either not in collection or is 0: do full update");
manager.updateAppWidget(widgetID, views);
}
else
{
Log.e("buildUpdate -- WidgetUpdateService", "buildUpdate -- WidgetUpdateService: is not 0: do partial update");
manager.partiallyUpdateAppWidget(widgetID, views);
}
with the modified logic, when the view is needing for a refresh/update (which we cannot control most of the time like orientation change). it will not override the whole view and just the partial view.
I have a clock widget that updates every minute. It renders a bitmap and replaces an imageview. This is to use a custom font in a widget. Below I showed the important pieces of my code. My problem is that the widget is there, but nothing shows up. I can still tap the widget to bring up the settings, so I know it's there. It's like the service update isn't working correctly in Kitkat but it does in Lollipop. Any suggestions?
public class DigitalClockWidget_2x1 extends AppWidgetProvider {
public RemoteViews mRemoteViews;
static String APP_SETTINGS = "8BitSettings";
#Override
public void onEnabled(Context context) {
super.onEnabled(context);
context.startService(new Intent(UpdateTimeService.UPDATE_TIME));
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
mRemoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
Intent LaunchIntent = getLaunchIntent(context);
PendingIntent clickPendIntent = PendingIntent.getActivity(context, 0, LaunchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mRemoteViews.setOnClickPendingIntent(R.id.widget_root, clickPendIntent);
ComponentName componentName = new ComponentName(context.getPackageName(),DigitalClockWidget_2x1.class.getName());
appWidgetManager.updateAppWidget(componentName, mRemoteViews);
context.startService(new Intent(UpdateTimeService.UPDATE_TIME));
}
public static Intent getLaunchIntent(Context context){
SharedPreferences clockSettings = context.getSharedPreferences("ClockSettings", 0);
String launchString = clockSettings.getString("tappedAction", APP_SETTINGS);
if(launchString.compareTo(APP_SETTINGS) == 0){
return new Intent(context, SettingsPage.class);
}
return context.getPackageManager().getLaunchIntentForPackage(launchString);
}
public static final class UpdateTimeService extends Service {
static final String UPDATE_TIME = "org.penguinproductions.eight_bit_clock.action.UPDATE_TIME_2x1";
RemoteViews mRemoteViews;
private Calendar mCalendar;
private final static IntentFilter mIntentFilter = new IntentFilter();
int textColor = 0;
boolean tweentyfourHour = false;
SharedPreferences clockSettings;
String APP_SETTINGS = "8BitSettings";
static {
mIntentFilter.addAction(Intent.ACTION_TIME_TICK);
mIntentFilter.addAction(Intent.ACTION_TIME_CHANGED);
mIntentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
}
#Override
public void onCreate() {
super.onCreate();
mCalendar = Calendar.getInstance();
registerReceiver(mTimeChangedReceiver, mIntentFilter);
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mTimeChangedReceiver);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if (intent != null) {
if (UPDATE_TIME.equals(intent.getAction())) {
updateTime();
}
}
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private final BroadcastReceiver mTimeChangedReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateTime();
}
};
private void updateTime() {
mCalendar.setTimeInMillis(System.currentTimeMillis());
mRemoteViews = new RemoteViews(getPackageName(), R.layout.widget);
String date = DateFormat.format(getString(R.string.date_format), mCalendar).toString();
mRemoteViews.setImageViewBitmap(R.id.imageView_txt, buildUpdate(getTodaysTime(), mCalendar.get(Calendar.AM_PM), date));
ComponentName mComponentName = new ComponentName(this, DigitalClockWidget_2x1.class);
AppWidgetManager mAppWidgetManager = AppWidgetManager.getInstance(this);
mAppWidgetManager.updateAppWidget(mComponentName, mRemoteViews);
Intent LaunchIntent = getLaunchIntent(getBaseContext());
PendingIntent clickPendIntent = PendingIntent.getActivity(getBaseContext(), 0, LaunchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mRemoteViews.setOnClickPendingIntent(R.id.widget_root, clickPendIntent);
mAppWidgetManager = AppWidgetManager.getInstance(getBaseContext());
mAppWidgetManager.updateAppWidget(mComponentName, mRemoteViews);
}
}
EDIT:
The issue seems to have to do with the Bitmap rendering. I replaced the imageview with a textview and it worked. So the Bitmap isn't displaying in KitKat, but it does in Lollipop
public Bitmap buildUpdate(String time, int AMPM, String date) {
Log.v("Penguin", "Building time string:" + time);
clockSettings = this.getSharedPreferences("ClockSettings", 0);
boolean showDate = clockSettings.getBoolean("showDate", true);
boolean showampm = clockSettings.getBoolean("ampm", true);
boolean leading0 = clockSettings.getBoolean("leading0", true);
textColor = clockSettings.getInt("clockColor", Color.WHITE);
int dateColor = clockSettings.getInt("dateColor", Color.WHITE);
Bitmap myBitmap = Bitmap.createBitmap(2500, 1100, Bitmap.Config.ARGB_8888);
int fontSize = 425;
Canvas myCanvas = new Canvas(myBitmap);
Paint paint = new Paint();
Typeface clock = Typeface.createFromAsset(this.getAssets(), "fonts/PressStart2P.ttf");
paint.setAntiAlias(true);
paint.setSubpixelText(true);
paint.setTypeface(clock);
paint.setStyle(Paint.Style.FILL);
paint.setColor(textColor);
paint.setTextSize(fontSize);
paint.setTextAlign(Paint.Align.CENTER);
myCanvas.drawText(time, myBitmap.getWidth() / 2, fontSize+200, paint);
paint.setTextSize(100);
if(showampm) {
// alert("AMPM");
String ampm = "AM";
if (AMPM == 1) ampm = "PM";
myCanvas.drawText(ampm, (myBitmap.getWidth() / 2) + ((time.length() * fontSize) / 2) + 100, 300, paint);
}
paint.setTextSize(125);
if(showDate) {
paint.setColor(dateColor);
myCanvas.drawText(date, myBitmap.getWidth() / 2, (myBitmap.getHeight() / 2 + 400), paint);
}
return myBitmap;
}
So the issue was that the size limit for my older phone running KitKat only allows for texture sizes no bigger than 2048x2048 pixels. My bitmap was 2500x1100, so scaling it down has fixed the issue
My assumption is that I just do not fully understand widgets yet. Hopefully one of you guru's can see where my logic/thinking is flawed.
Ultimately what happens with my widget is that it eventually becomes unresponsive at very random intervals (usually > 5 hours).
My investigation so far has led me to believe that it's potentially a result of the OS running low on memory and my widget being recreated?
If that's the case, I would have thought that the OnUpdate() method would handle this but potentially I'm wrong here.
I have read pretty much every thread on here regarding widget unresponsiveness. The only one that showed promise for me was this one:
Android Homescreen Widget becomes Unresponsive
but I'm not using a service and not sure I need to.
The goal of the widget is to first check if the user has created a profile. This is done by checking for the existence of a local db along with a user record. If neither of these exist, the widget should display a "Get Started" image (which it does successfully).
Once the user taps on this image, they are launched into a profile creation wizard. Once the profile is created, the widget is updated from the app to display an image along with some caloric intake information.
There are three clickable items on the widget. The image and the two textviews. Each respectively launching a different activity in my app.
Here is the widget class:
public class bbi_widget extends AppWidgetProvider {
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
}
private static String week6Path = "";
public static RemoteViews getWidgetRemoteViews(Context context) {
Intent calorieCrushIntent = new Intent(context, calorie_crush.class);
Intent dashBoardIntent = new Intent(context, DashboardActivity.class);
PendingIntent calorieCrushPendingIntent = PendingIntent.getActivity(
context, 0, calorieCrushIntent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent dashboardPendingIntent = PendingIntent.getActivity(
context, 0, dashBoardIntent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews appWidgetViews = new RemoteViews(context.getPackageName(),
R.layout.initial_widget_layout);
appWidgetViews.setOnClickPendingIntent(R.id.surp_def_widgettextView, calorieCrushPendingIntent);
appWidgetViews.setOnClickPendingIntent(R.id.calTextView, calorieCrushPendingIntent);
appWidgetViews.setOnClickPendingIntent(R.id.widget_after_picture, dashboardPendingIntent);
return appWidgetViews;
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
BBIDatabase db = new BBIDatabase(context);
db.openToRead();
boolean doesTableExist = db.doesTableExist(BBIDatabase.BBI_USER_TABLE);
db.close();
boolean doesUserExist = false;
if (doesTableExist){
db.openToRead();
doesUserExist = db.doesUserExist();
db.close();
}
if (!doesTableExist || !doesUserExist){
Intent getStartedIntent = new Intent(context, GettingStartedWizardActivity.class);
PendingIntent getStartedPendingIntent = PendingIntent.getActivity(
context, 0, getStartedIntent, PendingIntent.FLAG_UPDATE_CURRENT);
for (int index = 0; index < appWidgetIds.length; index++) {
int appWidgetId = appWidgetIds[index];
RemoteViews appWidgetViews = getWidgetRemoteViews(context);
appWidgetViews.setOnClickPendingIntent(R.id.widget_after_picture, getStartedPendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, appWidgetViews);
}
} else {
db.openToRead();
String curPath = db.GetSixWeekPath();
Bitmap sixWeekBmp = null;
if (week6Path != curPath && curPath != null && week6Path != null) {
week6Path = db.GetSixWeekPath();
sixWeekBmp = BitmapFactory.decodeFile(week6Path);
}
db.close();
db.openToRead();
int totalCalsToday = db.GetTodaysCalorieIntakeForWidget();
int bmrWithAct = db.GetBMRPlusActivity();
int additionalCalsCrushed = db.GetTodaysCaloriesBurnedForWidget();
int surp = totalCalsToday - (bmrWithAct + additionalCalsCrushed);
if (surp < 0)
surp = 0;
int def = totalCalsToday - (bmrWithAct + additionalCalsCrushed);
if (def > 0)
def = 0;
db.close();
for (int index = 0; index < appWidgetIds.length; index++) {
int appWidgetId = appWidgetIds[index];
RemoteViews appWidgetViews = getWidgetRemoteViews(context);
appWidgetViews.setViewVisibility(R.id.calTextView, View.VISIBLE);
appWidgetViews.setViewVisibility(R.id.surp_def_widgettextView, View.VISIBLE);
appWidgetViews.setTextViewText(R.id.calTextView, "Calorie intake: " + String.valueOf(totalCalsToday));
if (surp > 0) {
appWidgetViews.setTextViewText(R.id.surp_def_widgettextView, "SURPLUS " + String.valueOf(surp));
appWidgetViews.setTextColor(R.id.surp_def_widgettextView, context.getResources().getColor(R.color.surplus_ball_color));
} else {
appWidgetViews.setTextViewText(R.id.surp_def_widgettextView, "DEFICIT " + String.valueOf(def));
appWidgetViews.setTextColor(R.id.surp_def_widgettextView, context.getResources().getColor(R.color.calorie_crush_ball));
}
appWidgetViews.setImageViewBitmap(R.id.widget_after_picture, sixWeekBmp);
Intent calorieCrushIntent = new Intent(context, calorie_crush.class);
Intent dashBoardIntent = new Intent(context, DashboardActivity.class);
PendingIntent calorieCrushPendingIntent = PendingIntent.getActivity(
context, 0, calorieCrushIntent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent dashboardPendingIntent = PendingIntent.getActivity(
context, 0, dashBoardIntent, PendingIntent.FLAG_UPDATE_CURRENT);
appWidgetViews.setOnClickPendingIntent(R.id.surp_def_widgettextView, calorieCrushPendingIntent);
appWidgetViews.setOnClickPendingIntent(R.id.calTextView, calorieCrushPendingIntent);
appWidgetViews.setOnClickPendingIntent(R.id.widget_after_picture, dashboardPendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, appWidgetViews);
}
}
}
}
From my app, I do update these values in the widget using remoteViews.
Here is the helper class in my app:
public class WidgetHelper {
public static void UpdateCalorieIntake(int newValue, Context context) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.initial_widget_layout);
ComponentName thisWidget = new ComponentName(context, bbi_widget.class);
remoteViews.setTextViewText(R.id.calTextView, "Calories in " + String.valueOf(newValue));
appWidgetManager.updateAppWidget(thisWidget, remoteViews);
}
public static void UpdateWidgetSurplus(int newValue, Context context) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.initial_widget_layout);
ComponentName thisWidget = new ComponentName(context, bbi_widget.class);
if (newValue > 0) {
remoteViews.setTextViewText(R.id.surp_def_widgettextView, "Caloric Surplus " + String.valueOf(newValue));
remoteViews.setTextColor(R.id.surp_def_widgettextView, context.getResources().getColor(R.color.surplus_ball_color));
} else {
remoteViews.setTextViewText(R.id.surp_def_widgettextView, "Caloric Deficit " + String.valueOf(newValue));
remoteViews.setTextColor(R.id.surp_def_widgettextView, context.getResources().getColor(R.color.calorie_crush_ball));
}
appWidgetManager.updateAppWidget(thisWidget, remoteViews);
}
private static String week6Path = "";
public static void UpdateAll(Context context) {
BBIDatabase db = new BBIDatabase(context);
db.openToRead();
String curPath = db.GetSixWeekPath();
Bitmap sixWeekBmp = null;
if (week6Path != curPath && curPath != null && week6Path != null) {
week6Path = db.GetSixWeekPath();
sixWeekBmp = BitmapFactory.decodeFile(week6Path);
}
db.close();
db.openToRead();
int totalCalsToday = db.GetTodaysCalorieIntakeForWidget();
int bmrWithAct = db.GetBMRPlusActivity();
int additionalCalsCrushed = db.GetTodaysCaloriesBurnedForWidget();
int surp = totalCalsToday - (bmrWithAct + additionalCalsCrushed);
if (surp < 0)
surp = 0;
int def = totalCalsToday - (bmrWithAct + additionalCalsCrushed);
if (def > 0)
def = 0;
db.close();
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
RemoteViews appWidgetViews = new RemoteViews(context.getPackageName(), R.layout.initial_widget_layout);
ComponentName thisWidget = new ComponentName(context, bbi_widget.class);
appWidgetViews.setTextViewText(R.id.calTextView, "Calorie intake: " + String.valueOf(totalCalsToday));
if (surp > 0) {
appWidgetViews.setTextViewText(R.id.surp_def_widgettextView, "Caloric surplus " + String.valueOf(surp));
appWidgetViews.setTextColor(R.id.surp_def_widgettextView, context.getResources().getColor(R.color.surplus_ball_color));
} else {
appWidgetViews.setTextViewText(R.id.surp_def_widgettextView, "Caloric deficit " + String.valueOf(def));
appWidgetViews.setTextColor(R.id.surp_def_widgettextView, context.getResources().getColor(R.color.calorie_crush_ball));
}
appWidgetViews.setImageViewBitmap(R.id.widget_after_picture, sixWeekBmp);
Intent calorieCrushIntent = new Intent(context, calorie_crush.class);
Intent dashBoardIntent = new Intent(context, DashboardActivity.class);
PendingIntent calorieCrushPendingIntent = PendingIntent.getActivity(
context, 0, calorieCrushIntent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent dashboardPendingIntent = PendingIntent.getActivity(
context, 0, dashBoardIntent, PendingIntent.FLAG_UPDATE_CURRENT);
appWidgetViews.setOnClickPendingIntent(R.id.surp_def_widgettextView, calorieCrushPendingIntent);
appWidgetViews.setOnClickPendingIntent(R.id.calTextView, calorieCrushPendingIntent);
appWidgetViews.setOnClickPendingIntent(R.id.widget_after_picture, dashboardPendingIntent);
appWidgetManager.updateAppWidget(thisWidget, appWidgetViews);
}
}
Provider infor:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="294dp"
android:minHeight="294dp"
android:previewImage="#drawable/bbi_icon"
android:initialLayout="#layout/initial_widget_layout"
>
</appwidget-provider>
I am allowing the user to change the icon in the class Personalize by sending a request code holding an image from a user gallery.
The setIconImageinWidget() method sends the result here (in Drag_and_Drop_App):
else if(requestCode == RESULT_ICON){
byte[] byteArray = data.getByteArrayExtra("myIconBitmap");
Bitmap myIcon = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
setBackgroundImageForIcon(myIcon);
Log.d("Drag_and_Drop_App", "Icon is set");
}
}
Here is the setBackgroundImageForIcon method:
#SuppressLint("NewApi")
private void setBackgroundImageForIcon(Bitmap bitmap) {
ImageView ivICON = (ImageView) findViewById(R.id.bwidgetOpen);
Drawable dq = new BitmapDrawable(getResources(), bitmap);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
ivICON.setImageDrawable(dq);
} else {
ivICON.setImageDrawable(dq);
Log.d("Drag_and_Drop_App", "Icon is set");
}
}
This returns no errors but the icon is not changed at all based on whatever picture the user chooses to use.
After looking around a while I realized that I would have to change the app widget provider section of my coding here:
package com.example.awesomefilebuilderwidget;
IMPORTS
public class AFBWidget extends AppWidgetProvider{
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// TODO Auto-generated method stub
super.onUpdate(context, appWidgetManager, appWidgetIds);
Random r = new Random();
int randomInt = r.nextInt(1000000000);
String rand = String.valueOf(randomInt);
final int N = appWidgetIds.length;
for (int i = 0; i < N; i++){
int awID = appWidgetIds[i];
RemoteViews v = new RemoteViews(context.getPackageName(), R.layout.widget);
v.setTextViewText(R.id.tvwidgetUpdate, rand);
Intent configIntent = new Intent(context, Drag_and_Drop_App.class);
PendingIntent configPendingIntent = PendingIntent.getActivity(context, 0, configIntent, PendingIntent.FLAG_UPDATE_CURRENT);
v.setOnClickPendingIntent(R.id.bwidgetOpen, configPendingIntent);
//me trying to set the Bitmap from the above classes somehow... v.setImageViewBitmap(R.id.bwidgetOpen, R.id.);
appWidgetManager.updateAppWidget(awID, v);
}
}
#Override
public void onDeleted(Context context, int[] appWidgetIds) {
// TODO Auto-generated method stub
super.onDeleted(context, appWidgetIds);
Toast.makeText(context, "Thanks for checking us out!", Toast.LENGTH_SHORT).show();
}
}
And the imageView I am changing is this:
<ImageView
android:id="#+id/bwidgetOpen"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_launcher"
android:contentDescription="#string/desc"/>
in Widget.xml
How can I change my Widget Provider so that it will allow the changing of the icon?
I know this is a lot to read but any help is apperciated!
UPDATED:
#SuppressLint("NewApi")
private void setBackgroundImageForIcon(Bitmap bitmap) {
Log.d("Drag_and_Drop_App", "Icon...");
ImageView ivICON = (ImageView) findViewById(R.id.bwidgetOpen);
BitmapDrawable dq = new BitmapDrawable(getResources(), bitmap);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
// ivICON.setImageDrawable(dq);
ivICON.setImageResource(R.drawable.pattern1);
} else {
// ivICON.setImageDrawable(dq);
ivICON.setImageResource(R.drawable.pattern1);
Log.d("Drag_and_Drop_App", "Icon is set");
}
}
I've pretty much given up on dynamic remoteviews, but I still have about 20 remoteViews with 3-4 method calls on each in my onUpdate method. Now the problem is, can I have an iterator on RemoteViews subView id for a loop?
EDIT
Ok, here's the code, I tried using bookmarkcounter as a iterator since the R class generates R.id.widget* * as a incrementing number (by one). But it doesn't work.
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
Cursor cursor;
String SORT_BY_COLUMN = Constants.SORT_BY_COLUMN;
String SORT_ORDER = Constants.SORT_ORDER;
int bookmarkIdCounter = R.id.widget_bookmark_1;
Bitmap bitmap;
HashMap<Integer, String> urls = new HashMap<Integer, String>();
ComponentName thisWidget = new ComponentName(context, WidgetProvider.class);
RemoteViews updateViews = new RemoteViews(
context.getPackageName(), R.layout.widget_main);
RemoteViews bookmarks = new RemoteViews(
context.getPackageName(), R.layout.widget_bookmarks);;
cursor = context.getContentResolver().query(
Browser.BOOKMARKS_URI, Constants.projection, Constants.selection,
null, SORT_BY_COLUMN + " " + SORT_ORDER);
if(cursor.moveToFirst()) {
ByteArrayInputStream blobImage;
do{
blobImage = new ByteArrayInputStream(
cursor.getBlob(cursor.getColumnIndex(BookmarkColumns.FAVICON)));
bitmap = BitmapFactory.decodeStream(blobImage);
bitmap = Bitmap.createScaledBitmap(
bitmap, Constants.FAVICON_SIZE, Constants.FAVICON_SIZE, false);
bookmarks.setImageViewBitmap(bookmarkIdCounter, bitmap);
bookmarks.setInt(bookmarkIdCounter, "setBackgroundColor", Color.WHITE);
urls.put(bookmarkIdCounter,
cursor.getString(
cursor.getColumnIndex(BookmarkColumns.URL)));
bookmarkIdCounter++;
} while (cursor.moveToNext() && (bookmarkIdCounter < 2));
}
updateViews.addView(R.id.widget_main_container, bookmarks);
cursor.deactivate();
appWidgetManager.updateAppWidget(thisWidget, updateViews);
}
RemoteViews is not a View nor does it contain Views.
It is a way to "describe" a View and have it created in some other process. Basically it's just a set of actions that must be performed to build a View.
As there are no Views inside it there is no way to retrieve/iterate a list of subViews.