OSDN Git Service

Rename mAppWidgetManager to appWidgetManager
[android-x86/packages-apps-Taskbar.git] / app / src / main / java / com / farmerbb / taskbar / ui / DashboardController.java
1 /* Based on code by Leonardo Fischer
2  * See https://github.com/lgfischer/WidgetHostExample
3  *
4  * Copyright 2016 Braden Farmer
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 package com.farmerbb.taskbar.ui;
20
21 import android.animation.Animator;
22 import android.animation.AnimatorListenerAdapter;
23 import android.annotation.SuppressLint;
24 import android.annotation.TargetApi;
25 import android.appwidget.AppWidgetHost;
26 import android.appwidget.AppWidgetHostView;
27 import android.appwidget.AppWidgetManager;
28 import android.appwidget.AppWidgetProviderInfo;
29 import android.content.BroadcastReceiver;
30 import android.content.ComponentName;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.SharedPreferences;
34 import android.content.pm.PackageManager;
35 import android.content.res.Configuration;
36 import android.graphics.Color;
37 import android.graphics.ColorMatrix;
38 import android.graphics.ColorMatrixColorFilter;
39 import android.graphics.drawable.Drawable;
40 import android.os.Build;
41 import android.os.Bundle;
42 import android.os.Handler;
43 import android.os.Process;
44
45 import androidx.annotation.VisibleForTesting;
46 import androidx.core.graphics.ColorUtils;
47 import android.util.SparseArray;
48 import android.view.MotionEvent;
49 import android.view.PointerIcon;
50 import android.view.View;
51 import android.view.ViewGroup;
52 import android.view.WindowManager;
53 import android.widget.FrameLayout;
54 import android.widget.ImageView;
55 import android.widget.LinearLayout;
56 import android.widget.TextView;
57 import android.widget.Toast;
58
59 import com.farmerbb.taskbar.R;
60 import com.farmerbb.taskbar.activity.DashboardActivity;
61 import com.farmerbb.taskbar.helper.LauncherHelper;
62 import com.farmerbb.taskbar.util.TaskbarPosition;
63 import com.farmerbb.taskbar.helper.DashboardHelper;
64 import com.farmerbb.taskbar.widget.DashboardCell;
65 import com.farmerbb.taskbar.helper.FreeformHackHelper;
66 import com.farmerbb.taskbar.util.U;
67
68 import java.util.List;
69
70 import static com.farmerbb.taskbar.util.Constants.*;
71
72 public class DashboardController extends UIController {
73     private AppWidgetManager appWidgetManager;
74     private AppWidgetHost mAppWidgetHost;
75
76     private LinearLayout layout;
77
78     private SparseArray<DashboardCell> cells = new SparseArray<>();
79     private SparseArray<AppWidgetHostView> widgets = new SparseArray<>();
80
81     private final int APPWIDGET_HOST_ID = 123;
82
83     private int columns;
84     private int rows;
85     private int maxSize;
86     private int previouslySelectedCell = -1;
87
88     private View.OnClickListener ocl = view -> toggleDashboard();
89
90     private View.OnClickListener cellOcl = view -> cellClick(view, true);
91
92     private View.OnHoverListener cellOhl = (v, event) -> {
93         cellClick(v, false);
94
95         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
96             v.setPointerIcon(PointerIcon.getSystemIcon(context, PointerIcon.TYPE_DEFAULT));
97
98         return false;
99     };
100
101     private View.OnLongClickListener olcl = v -> {
102         cellLongClick(v);
103         return true;
104     };
105
106     private View.OnGenericMotionListener ogml = (view, motionEvent) -> {
107         if(motionEvent.getAction() == MotionEvent.ACTION_BUTTON_PRESS
108                 && motionEvent.getButtonState() == MotionEvent.BUTTON_SECONDARY)
109             cellLongClick(view);
110
111         return false;
112     };
113
114     private DashboardCell.OnInterceptedLongPressListener listener = this::cellLongClick;
115
116     private BroadcastReceiver toggleReceiver = new BroadcastReceiver() {
117         @Override
118         public void onReceive(Context context, Intent intent) {
119             toggleDashboard();
120         }
121     };
122
123     private BroadcastReceiver addWidgetReceiver = new BroadcastReceiver() {
124         @Override
125         public void onReceive(Context context, Intent intent) {
126             fadeIn();
127             addWidget(intent);
128         }
129     };
130
131     private BroadcastReceiver removeWidgetReceiver = new BroadcastReceiver() {
132         @Override
133         public void onReceive(Context context, Intent intent) {
134             fadeIn();
135
136             if(intent.hasExtra(EXTRA_CELL_ID)) {
137                 int cellId = intent.getExtras().getInt(EXTRA_CELL_ID, -1);
138
139                 removeWidget(cellId, false);
140             }
141         }
142     };
143
144     private BroadcastReceiver hideReceiver = new BroadcastReceiver() {
145         @Override
146         public void onReceive(Context context, Intent intent) {
147             hideDashboard();
148         }
149     };
150
151     public DashboardController(Context context) {
152         super(context);
153     }
154
155     @TargetApi(Build.VERSION_CODES.M)
156     @Override
157     public void onCreateHost(UIHost host) {
158         if(U.getBooleanPrefWithDefault(context, PREF_DASHBOARD))
159             init(context, host, () -> drawDashboard(host));
160         else
161             host.terminate();
162     }
163
164     @SuppressLint("RtlHardcoded")
165     private void drawDashboard(UIHost host) {
166         final ViewParams params = new ViewParams(
167                 WindowManager.LayoutParams.MATCH_PARENT,
168                 WindowManager.LayoutParams.MATCH_PARENT,
169                 -1,
170                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
171                 getBottomMargin(context, host)
172         );
173
174         // Initialize views
175         layout = new LinearLayout(context);
176         layout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
177         layout.setVisibility(View.GONE);
178         layout.setAlpha(0);
179
180         SharedPreferences pref = U.getSharedPreferences(context);
181         int width = U.getIntPrefWithDefault(context, PREF_DASHBOARD_WIDTH);
182         int height = U.getIntPrefWithDefault(context, PREF_DASHBOARD_HEIGHT);
183
184         int orientation = U.getDisplayOrientation(context);
185         boolean isPortrait = orientation == Configuration.ORIENTATION_PORTRAIT;
186         boolean isLandscape = orientation == Configuration.ORIENTATION_LANDSCAPE;
187
188         if(isPortrait) {
189             columns = height;
190             rows = width;
191         }
192
193         if(isLandscape) {
194             columns = width;
195             rows = height;
196         }
197
198         maxSize = columns * rows;
199
200         int backgroundTint = U.getBackgroundTint(context);
201         int accentColor = U.getAccentColor(context);
202         int accentColorAlt = accentColor;
203         accentColorAlt = ColorUtils.setAlphaComponent(accentColorAlt, Color.alpha(accentColorAlt) / 3);
204
205         int cellCount = 0;
206
207         for(int i = 0; i < columns; i++) {
208             LinearLayout layout2 = new LinearLayout(context);
209             layout2.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1));
210             layout2.setOrientation(LinearLayout.VERTICAL);
211
212             for(int j = 0; j < rows; j++) {
213                 DashboardCell cellLayout = (DashboardCell) View.inflate(context, R.layout.tb_dashboard, null);
214                 cellLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1));
215                 cellLayout.setBackgroundColor(backgroundTint);
216                 cellLayout.setOnClickListener(cellOcl);
217                 cellLayout.setOnHoverListener(cellOhl);
218                 cellLayout.setFocusable(false);
219
220                 TextView empty = cellLayout.findViewById(R.id.empty);
221                 empty.setBackgroundColor(accentColorAlt);
222                 empty.setTextColor(accentColor);
223
224                 Bundle bundle = new Bundle();
225                 bundle.putInt(EXTRA_CELL_ID, cellCount);
226
227                 cellLayout.setTag(bundle);
228                 cells.put(cellCount, cellLayout);
229                 cellCount++;
230
231                 layout2.addView(cellLayout);
232             }
233
234             layout.addView(layout2);
235         }
236
237         appWidgetManager = AppWidgetManager.getInstance(context);
238         mAppWidgetHost = new AppWidgetHost(context, APPWIDGET_HOST_ID);
239         mAppWidgetHost.startListening();
240
241         for(int i = 0; i < maxSize; i++) {
242             int appWidgetId = pref.getInt(PREF_DASHBOARD_WIDGET_PREFIX + i, -1);
243             if (appWidgetId != -1) {
244                 addWidget(appWidgetId, i, false);
245             } else if (pref.getBoolean(generateProviderPlaceholderPrefKey(i), false)) {
246                 addPlaceholder(i);
247             }
248         }
249
250         mAppWidgetHost.stopListening();
251
252         U.registerReceiver(context, toggleReceiver, ACTION_TOGGLE_DASHBOARD);
253         U.registerReceiver(context, addWidgetReceiver, ACTION_ADD_WIDGET_COMPLETED);
254         U.registerReceiver(context, removeWidgetReceiver, ACTION_REMOVE_WIDGET_COMPLETED);
255         U.registerReceiver(context, hideReceiver, ACTION_HIDE_DASHBOARD);
256
257         host.addView(layout, params);
258
259         new Handler().postDelayed(() ->
260                 updatePaddingSize(
261                         context,
262                         layout,
263                         TaskbarPosition.getTaskbarPosition(context)
264                 ),
265                 100
266         );
267     }
268
269     @VisibleForTesting
270     void updatePaddingSize(Context context, LinearLayout layout, String position) {
271         int paddingSize = context.getResources().getDimensionPixelSize(R.dimen.tb_icon_size);
272
273         switch(position) {
274             case POSITION_TOP_VERTICAL_LEFT:
275             case POSITION_BOTTOM_VERTICAL_LEFT:
276                 layout.setPadding(paddingSize, 0, 0, 0);
277                 break;
278             case POSITION_TOP_LEFT:
279             case POSITION_TOP_RIGHT:
280                 layout.setPadding(0, paddingSize, 0, 0);
281                 break;
282             case POSITION_TOP_VERTICAL_RIGHT:
283             case POSITION_BOTTOM_VERTICAL_RIGHT:
284                 layout.setPadding(0, 0, paddingSize, 0);
285                 break;
286             case POSITION_BOTTOM_LEFT:
287             case POSITION_BOTTOM_RIGHT:
288                 layout.setPadding(0, 0, 0, paddingSize);
289                 break;
290         }
291     }
292
293     private void toggleDashboard() {
294         if(layout.getVisibility() == View.GONE)
295             showDashboard();
296         else
297             hideDashboard();
298     }
299
300     @TargetApi(Build.VERSION_CODES.N)
301     private void showDashboard() {
302         if(layout.getVisibility() == View.GONE) {
303             layout.setOnClickListener(ocl);
304             fadeIn();
305
306             U.sendBroadcast(context, ACTION_DASHBOARD_APPEARING);
307             U.sendBroadcast(context, ACTION_HIDE_START_MENU);
308
309             boolean inFreeformMode = FreeformHackHelper.getInstance().isInFreeformWorkspace();
310
311             Intent intent = U.getThemedIntent(context, DashboardActivity.class);
312             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
313             intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
314
315             if (inFreeformMode) {
316                 if (U.hasBrokenSetLaunchBoundsApi()) {
317                     intent.putExtra(EXTRA_CONTEXT_MENU_FIX, true);
318                 }
319
320                 U.startActivityMaximized(context, intent);
321             } else {
322                 context.startActivity(intent);
323             }
324
325             for(int i = 0; i < maxSize; i++) {
326                 final DashboardCell cellLayout = cells.get(i);
327                 final AppWidgetHostView hostView = widgets.get(i);
328
329                 if(hostView != null) {
330                     try {
331                         context.getPackageManager().getApplicationInfo(hostView.getAppWidgetInfo().provider.getPackageName(), 0);
332                         hostView.post(() -> {
333                             ViewGroup.LayoutParams params = hostView.getLayoutParams();
334                             params.width = cellLayout.getWidth();
335                             params.height = cellLayout.getHeight();
336                             hostView.setLayoutParams(params);
337                             hostView.updateAppWidgetSize(null, cellLayout.getWidth(), cellLayout.getHeight(), cellLayout.getWidth(), cellLayout.getHeight());
338                         });
339                     } catch (PackageManager.NameNotFoundException e) {
340                         removeWidget(i, false);
341                     } catch (NullPointerException e) {
342                         removeWidget(i, true);
343                     }
344                 }
345             }
346
347             showDashboardTutorialToast(context);
348         }
349     }
350
351     @VisibleForTesting
352     void showDashboardTutorialToast(Context context) {
353         final SharedPreferences pref = U.getSharedPreferences(context);
354         if(!pref.getBoolean(PREF_DASHBOARD_TUTORIAL_SHOWN, false)) {
355             U.showToastLong(context, R.string.tb_dashboard_tutorial);
356             pref.edit().putBoolean(PREF_DASHBOARD_TUTORIAL_SHOWN, true).apply();
357         }
358     }
359
360     private void hideDashboard() {
361         if(layout.getVisibility() == View.VISIBLE) {
362             layout.setOnClickListener(null);
363             fadeOut(true);
364
365             for(int i = 0; i < maxSize; i++) {
366                 FrameLayout frameLayout = cells.get(i);
367                 frameLayout.findViewById(R.id.empty).setVisibility(View.GONE);
368             }
369
370             previouslySelectedCell = -1;
371         }
372     }
373
374     private void fadeIn() {
375         mAppWidgetHost.startListening();
376
377         DashboardHelper.getInstance().setDashboardOpen(true);
378
379         layout.setVisibility(View.VISIBLE);
380         layout.animate()
381                 .alpha(1)
382                 .setDuration(context.getResources().getInteger(android.R.integer.config_shortAnimTime))
383                 .setListener(null);
384     }
385
386     private void fadeOut(final boolean sendIntent) {
387         mAppWidgetHost.stopListening();
388
389         DashboardHelper.getInstance().setDashboardOpen(false);
390
391         layout.animate()
392                 .alpha(0)
393                 .setDuration(context.getResources().getInteger(android.R.integer.config_shortAnimTime))
394                 .setListener(new AnimatorListenerAdapter() {
395                     @Override
396                     public void onAnimationEnd(Animator animation) {
397                         layout.setVisibility(View.GONE);
398                         if(sendIntent) {
399                             U.sendBroadcast(context, ACTION_DASHBOARD_DISAPPEARING);
400                         }
401                     }
402                 });
403     }
404
405     @TargetApi(Build.VERSION_CODES.M)
406     @Override
407     public void onRecreateHost(UIHost host) {
408         if(layout != null) {
409             try {
410                 host.removeView(layout);
411             } catch (IllegalArgumentException e) { /* Gracefully fail */ }
412
413             SharedPreferences pref = U.getSharedPreferences(context);
414             if(U.canDrawOverlays(context))
415                 drawDashboard(host);
416             else {
417                 pref.edit().putBoolean(PREF_TASKBAR_ACTIVE, false).apply();
418
419                 host.terminate();
420             }
421         }
422     }
423
424     @Override
425     public void onDestroyHost(UIHost host) {
426         if(layout != null)
427             try {
428                 host.removeView(layout);
429             } catch (IllegalArgumentException e) { /* Gracefully fail */ }
430
431         U.unregisterReceiver(context, toggleReceiver);
432         U.unregisterReceiver(context, addWidgetReceiver);
433         U.unregisterReceiver(context, removeWidgetReceiver);
434         U.unregisterReceiver(context, hideReceiver);
435
436         SharedPreferences pref = U.getSharedPreferences(context);
437         if(!LauncherHelper.getInstance().isOnSecondaryHomeScreen(context)
438                 || !pref.getBoolean(PREF_DONT_STOP_DASHBOARD, false))
439             U.sendBroadcast(context, ACTION_DASHBOARD_DISAPPEARING);
440
441         pref.edit().remove(PREF_DONT_STOP_DASHBOARD).apply();
442     }
443
444     private void cellClick(View view, boolean isActualClick) {
445         Bundle bundle = (Bundle) view.getTag();
446         int cellId = bundle.getInt(EXTRA_CELL_ID);
447         int appWidgetId = bundle.getInt(EXTRA_APPWIDGET_ID, -1);
448
449         int currentlySelectedCell = appWidgetId == -1 ? cellId : -1;
450
451         SharedPreferences pref = U.getSharedPreferences(context);
452         boolean shouldShowPlaceholder =
453                 pref.getBoolean(generateProviderPlaceholderPrefKey(cellId), false);
454         if(isActualClick && ((appWidgetId == -1 && currentlySelectedCell == previouslySelectedCell) || shouldShowPlaceholder)) {
455             fadeOut(false);
456
457             FrameLayout frameLayout = cells.get(currentlySelectedCell);
458             frameLayout.findViewById(R.id.empty).setVisibility(View.GONE);
459
460             Intent intent = new Intent(ACTION_ADD_WIDGET_REQUESTED);
461             intent.putExtra(EXTRA_APPWIDGET_ID, APPWIDGET_HOST_ID);
462             intent.putExtra(EXTRA_CELL_ID, cellId);
463             U.sendBroadcast(context, intent);
464
465             if(shouldShowPlaceholder) {
466                 String providerName =
467                         pref.getString(generateProviderPrefKey(cellId), PREF_DEFAULT_NULL);
468                 if(!providerName.equals(PREF_DEFAULT_NULL)) {
469                     ComponentName componentName = ComponentName.unflattenFromString(providerName);
470
471                     List<AppWidgetProviderInfo> providerInfoList = appWidgetManager.getInstalledProvidersForProfile(Process.myUserHandle());
472                     for(AppWidgetProviderInfo info : providerInfoList) {
473                         if(info.provider.equals(componentName)) {
474                             U.showToast(context, context.getString(R.string.tb_widget_restore_toast, info.loadLabel(context.getPackageManager())), Toast.LENGTH_SHORT);
475                             break;
476                         }
477                     }
478                 }
479             }
480
481             previouslySelectedCell = -1;
482         } else {
483             for(int i = 0; i < maxSize; i++) {
484                 FrameLayout frameLayout = cells.get(i);
485                 frameLayout.findViewById(R.id.empty).setVisibility(i == currentlySelectedCell && !shouldShowPlaceholder ? View.VISIBLE : View.GONE);
486             }
487
488             previouslySelectedCell = currentlySelectedCell;
489         }
490     }
491
492     @VisibleForTesting
493     String generateProviderPrefKey(int cellId) {
494         return PREF_DASHBOARD_WIDGET_PREFIX + cellId + PREF_DASHBOARD_WIDGET_PROVIDER_SUFFIX;
495     }
496
497     @VisibleForTesting
498     String generateProviderPlaceholderPrefKey(int cellId) {
499         return PREF_DASHBOARD_WIDGET_PREFIX + cellId + PREF_DASHBOARD_WIDGET_PLACEHOLDER_SUFFIX;
500     }
501
502     private void cellLongClick(View view) {
503         fadeOut(false);
504
505         Bundle bundle = (Bundle) view.getTag();
506         int cellId = bundle.getInt(EXTRA_CELL_ID);
507
508         Intent intent = new Intent(ACTION_REMOVE_WIDGET_REQUESTED);
509         intent.putExtra(EXTRA_CELL_ID, cellId);
510         U.sendBroadcast(context, intent);
511     }
512
513     @VisibleForTesting
514     void addWidget(Intent intent) {
515         if (intent.hasExtra(EXTRA_APPWIDGET_ID) && intent.hasExtra(EXTRA_CELL_ID)) {
516             int appWidgetId = intent.getExtras().getInt(EXTRA_APPWIDGET_ID, -1);
517             int cellId = intent.getExtras().getInt(EXTRA_CELL_ID, -1);
518
519             addWidget(appWidgetId, cellId, true);
520         }
521     }
522
523     private void addWidget(int appWidgetId, int cellId, boolean shouldSave) {
524         AppWidgetProviderInfo appWidgetInfo = appWidgetManager.getAppWidgetInfo(appWidgetId);
525
526         final DashboardCell cellLayout = cells.get(cellId);
527         final AppWidgetHostView hostView = mAppWidgetHost.createView(context, appWidgetId, appWidgetInfo);
528         hostView.setAppWidget(appWidgetId, appWidgetInfo);
529
530         Bundle bundle = new Bundle();
531         bundle.putInt(EXTRA_CELL_ID, cellId);
532         hostView.setTag(bundle);
533
534         cellLayout.findViewById(R.id.empty).setVisibility(View.GONE);
535         cellLayout.findViewById(R.id.placeholder).setVisibility(View.GONE);
536         cellLayout.setOnLongClickListener(olcl);
537         cellLayout.setOnGenericMotionListener(ogml);
538         cellLayout.setOnInterceptedLongPressListener(listener);
539
540         LinearLayout linearLayout = cellLayout.findViewById(R.id.dashboard);
541         linearLayout.addView(hostView);
542
543         Bundle bundle2 = (Bundle) cellLayout.getTag();
544         bundle2.putInt(EXTRA_APPWIDGET_ID, appWidgetId);
545         cellLayout.setTag(bundle2);
546
547         widgets.put(cellId, hostView);
548
549         if (shouldSave) {
550             saveWidgetInfo(context, appWidgetInfo, cellId, appWidgetId);
551         }
552
553         new Handler().post(() -> {
554             ViewGroup.LayoutParams params = hostView.getLayoutParams();
555             params.width = cellLayout.getWidth();
556             params.height = cellLayout.getHeight();
557             hostView.setLayoutParams(params);
558             hostView.updateAppWidgetSize(null, cellLayout.getWidth(), cellLayout.getHeight(), cellLayout.getWidth(), cellLayout.getHeight());
559         });
560     }
561
562     @VisibleForTesting
563     void saveWidgetInfo(Context context,
564                         AppWidgetProviderInfo appWidgetInfo,
565                         int cellId,
566                         int appWidgetId) {
567         SharedPreferences pref = U.getSharedPreferences(context);
568         SharedPreferences.Editor editor = pref.edit();
569         editor.putInt(PREF_DASHBOARD_WIDGET_PREFIX + cellId, appWidgetId);
570         editor.putString(
571                 generateProviderPrefKey(cellId),
572                 appWidgetInfo.provider.flattenToString()
573         );
574         editor.remove(generateProviderPlaceholderPrefKey(cellId));
575         editor.apply();
576     }
577
578     private void removeWidget(int cellId, boolean tempRemove) {
579         widgets.remove(cellId);
580
581         DashboardCell cellLayout = cells.get(cellId);
582         Bundle bundle = (Bundle) cellLayout.getTag();
583
584         mAppWidgetHost.deleteAppWidgetId(bundle.getInt(EXTRA_APPWIDGET_ID));
585         bundle.remove(EXTRA_APPWIDGET_ID);
586
587         LinearLayout linearLayout = cellLayout.findViewById(R.id.dashboard);
588         linearLayout.removeAllViews();
589
590         cellLayout.setTag(bundle);
591         cellLayout.setOnClickListener(cellOcl);
592         cellLayout.setOnHoverListener(cellOhl);
593         cellLayout.setOnLongClickListener(null);
594         cellLayout.setOnGenericMotionListener(null);
595         cellLayout.setOnInterceptedLongPressListener(null);
596
597         SharedPreferences pref = U.getSharedPreferences(context);
598         SharedPreferences.Editor editor = pref.edit();
599         editor.remove(PREF_DASHBOARD_WIDGET_PREFIX + cellId);
600
601         if (tempRemove) {
602             editor.putBoolean(generateProviderPlaceholderPrefKey(cellId), true);
603             addPlaceholder(cellId);
604         } else {
605             editor.remove(generateProviderPrefKey(cellId));
606         }
607         editor.apply();
608     }
609
610     private void addPlaceholder(int cellId) {
611         FrameLayout placeholder = cells.get(cellId).findViewById(R.id.placeholder);
612         SharedPreferences pref = U.getSharedPreferences(context);
613         String providerName = pref.getString(generateProviderPrefKey(cellId), PREF_DEFAULT_NULL);
614
615         if(!providerName.equals(PREF_DEFAULT_NULL)) {
616             ImageView imageView = placeholder.findViewById(R.id.placeholder_image);
617             ComponentName componentName = ComponentName.unflattenFromString(providerName);
618
619             List<AppWidgetProviderInfo> providerInfoList = appWidgetManager.getInstalledProvidersForProfile(Process.myUserHandle());
620             for(AppWidgetProviderInfo info : providerInfoList) {
621                 if(info.provider.equals(componentName)) {
622                     Drawable drawable = info.loadPreviewImage(context, -1);
623                     if(drawable == null) drawable = info.loadIcon(context, -1);
624
625                     ColorMatrix matrix = new ColorMatrix();
626                     matrix.setSaturation(0);
627
628                     imageView.setImageDrawable(drawable);
629                     imageView.setColorFilter(new ColorMatrixColorFilter(matrix));
630                     break;
631                 }
632             }
633         }
634
635         placeholder.setVisibility(View.VISIBLE);
636     }
637 }