Home | History | Annotate | Download | only in appwidget
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.widget.cts.appwidget;
     18 
     19 import android.app.PendingIntent;
     20 import android.appwidget.AppWidgetManager;
     21 import android.appwidget.AppWidgetProvider;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.net.Uri;
     25 import android.os.Handler;
     26 import android.os.Looper;
     27 import android.view.View;
     28 import android.widget.RemoteViews;
     29 import android.widget.cts.R;
     30 
     31 import com.android.compatibility.common.util.PollingCheck;
     32 
     33 import java.util.concurrent.CountDownLatch;
     34 
     35 public final class MyAppWidgetProvider extends AppWidgetProvider {
     36     private static final long TIME_SLICE = 100;
     37 
     38     public static final String KEY_DISPLAYED_CHILD_INDEX =
     39             "MyAppWidgetProvider.displayedChildIndex";
     40     public static final String KEY_SHOW_NEXT = "MyAppWidgetProvider.showNext";
     41     public static final String KEY_SHOW_PREVIOUS = "MyAppWidgetProvider.showPrevious";
     42     public static final String KEY_SWITCH_TO_LIST = "MyAppWidgetProvider.switchToList";
     43     public static final String KEY_SCROLL_POSITION = "MyAppWidgetProvider.scrollPosition";
     44     public static final String KEY_SCROLL_OFFSET = "MyAppWidgetProvider.scrollOffset";
     45 
     46     // This latch will be notified when onEnabled is called on our provider.
     47     private static CountDownLatch sCountDownLatch;
     48     // Gating condition to be polled to proceed with setScrollPosition call.
     49     private static PollingCheck.PollingCheckCondition sSetScrollCondition;
     50     // Gating condition to be polled to proceed with setRelativeScrollPosition call.
     51     private static PollingCheck.PollingCheckCondition sSetRelativeScrollCondition;
     52 
     53     private int mDisplayedChildIndex;
     54     private boolean mShowNext;
     55     private boolean mShowPrevious;
     56     private boolean mSwitchToList;
     57     private int mScrollPosition;
     58     private int mScrollOffset;
     59 
     60     public static void configure(CountDownLatch countDownLatch,
     61             PollingCheck.PollingCheckCondition setScrollCondition,
     62             PollingCheck.PollingCheckCondition setRelativeScrollCondition) {
     63         sCountDownLatch = countDownLatch;
     64         sSetScrollCondition = setScrollCondition;
     65         sSetRelativeScrollCondition = setRelativeScrollCondition;
     66     }
     67 
     68     @Override
     69     public void onReceive(Context context, Intent intent) {
     70         mDisplayedChildIndex = intent.getIntExtra(KEY_DISPLAYED_CHILD_INDEX, -1);
     71         mShowNext = intent.getBooleanExtra(KEY_SHOW_NEXT, false);
     72         mShowPrevious = intent.getBooleanExtra(KEY_SHOW_PREVIOUS, false);
     73         mSwitchToList = intent.getBooleanExtra(KEY_SWITCH_TO_LIST, false);
     74         mScrollPosition = intent.getIntExtra(KEY_SCROLL_POSITION, -1);
     75         mScrollOffset = intent.getIntExtra(KEY_SCROLL_OFFSET, 0);
     76 
     77         super.onReceive(context, intent);
     78     }
     79 
     80     @Override
     81     public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
     82         final int appWidgetId = appWidgetIds[0];
     83         final RemoteViews widgetAdapterView = new RemoteViews(context.getPackageName(),
     84                 R.layout.remoteviews_adapter);
     85 
     86         final Intent stackIntent = new Intent(context, MyAppWidgetService.class);
     87         stackIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
     88         stackIntent.setData(Uri.parse(stackIntent.toUri(Intent.URI_INTENT_SCHEME)));
     89 
     90         widgetAdapterView.setRemoteAdapter(R.id.remoteViews_stack, stackIntent);
     91         widgetAdapterView.setEmptyView(R.id.remoteViews_stack, R.id.remoteViews_empty);
     92 
     93         if (mDisplayedChildIndex >= 0) {
     94             widgetAdapterView.setDisplayedChild(R.id.remoteViews_stack, mDisplayedChildIndex);
     95         }
     96         if (mShowNext) {
     97             widgetAdapterView.showNext(R.id.remoteViews_stack);
     98         }
     99         if (mShowPrevious) {
    100             widgetAdapterView.showPrevious(R.id.remoteViews_stack);
    101         }
    102 
    103         // Here we setup the a pending intent template. Individuals items of a collection
    104         // cannot setup their own pending intents, instead, the collection as a whole can
    105         // setup a pending intent template, and the individual items can set a fillInIntent
    106         // to create unique before on an item to item basis.
    107         Intent viewIntent = new Intent(Intent.ACTION_VIEW,
    108                 Uri.parse("ctstest://RemoteView/testWidget"));
    109         PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, viewIntent,
    110                 PendingIntent.FLAG_UPDATE_CURRENT);
    111 
    112         widgetAdapterView.setPendingIntentTemplate(R.id.remoteViews_stack, pendingIntent);
    113 
    114         if (mSwitchToList) {
    115             final Intent listIntent = new Intent(context, MyAppWidgetService.class);
    116             listIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    117             listIntent.setData(Uri.parse(stackIntent.toUri(Intent.URI_INTENT_SCHEME)));
    118 
    119             widgetAdapterView.setRemoteAdapter(R.id.remoteViews_list, listIntent);
    120 
    121             widgetAdapterView.setViewVisibility(R.id.remoteViews_stack, View.GONE);
    122             widgetAdapterView.setViewVisibility(R.id.remoteViews_list, View.VISIBLE);
    123         }
    124 
    125         final Handler handler = new Handler(Looper.myLooper());
    126         if (mScrollPosition >= 0) {
    127             // We need to schedule the call to setScrollPosition as a separate event that runs
    128             // after the underlying ListView has been laid out on the screen. Otherwise calling
    129             // that API on a ListView with 0x0 dimension has no effect - the list content is only
    130             // populated via the adapter when ListView has "real" bounds.
    131             final Runnable setScrollRunnable = new Runnable() {
    132                 public void run() {
    133                     if (sSetScrollCondition.canProceed()) {
    134                         // Gating condition has been satisfied. Call setScrollPosition and
    135                         // ask the widget manager to update our widget
    136                         widgetAdapterView.setScrollPosition(R.id.remoteViews_list, mScrollPosition);
    137                         appWidgetManager.partiallyUpdateAppWidget(appWidgetId, widgetAdapterView);
    138                     } else {
    139                         // Keep on "waiting" until the gating condition is satisfied
    140                         handler.postDelayed(this, TIME_SLICE);
    141                     }
    142                 }
    143             };
    144             handler.postDelayed(setScrollRunnable, TIME_SLICE);
    145         }
    146 
    147         if (mScrollOffset != 0) {
    148             // We need to schedule the call to setRelativeScrollPosition as a separate event that
    149             // runs after the underlying ListView has been laid out on the screen. Otherwise calling
    150             // that API on a ListView with 0x0 dimension has no effect - the list content is only
    151             // populated via the adapter when ListView has "real" bounds.
    152             final Runnable setRelativeScrollRunnable = new Runnable() {
    153                 public void run() {
    154                     if (sSetRelativeScrollCondition.canProceed()) {
    155                         // Gating condition has been satisfied. Call setRelativeScrollPosition and
    156                         // ask the widget manager to update our widget
    157                         widgetAdapterView.setRelativeScrollPosition(
    158                                 R.id.remoteViews_list, mScrollOffset);
    159                         appWidgetManager.partiallyUpdateAppWidget(appWidgetId, widgetAdapterView);
    160                     } else {
    161                         // Keep on "waiting" until the gating condition is satisfied
    162                         handler.postDelayed(this, TIME_SLICE);
    163                     }
    164                 }
    165             };
    166             handler.postDelayed(setRelativeScrollRunnable, TIME_SLICE);
    167         }
    168 
    169         appWidgetManager.updateAppWidget(appWidgetId, widgetAdapterView);
    170 
    171         sCountDownLatch.countDown();
    172     }
    173 
    174     @Override
    175     public void onEnabled(Context context) {
    176         sCountDownLatch.countDown();
    177     }
    178 }
    179