Home | History | Annotate | Download | only in protips
      1 /*
      2  * Copyright (C) 2010 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 com.android.protips;
     18 
     19 import android.app.AlarmManager;
     20 import android.app.PendingIntent;
     21 import android.app.Service;
     22 import android.appwidget.AppWidgetManager;
     23 import android.appwidget.AppWidgetProvider;
     24 import android.content.BroadcastReceiver;
     25 import android.content.ComponentName;
     26 import android.content.Context;
     27 import android.content.SharedPreferences;
     28 import android.content.Intent;
     29 import android.content.res.Resources;
     30 import android.content.res.TypedArray;
     31 import android.graphics.drawable.Drawable;
     32 import android.net.Uri;
     33 import android.os.Bundle;
     34 import android.os.Handler;
     35 import android.os.HandlerThread;
     36 import android.os.IBinder;
     37 import android.os.Looper;
     38 import android.os.Message;
     39 import android.os.SystemClock;
     40 import android.text.format.Time;
     41 import android.text.Spannable;
     42 import android.util.Log;
     43 import android.view.View;
     44 import android.widget.RemoteViews;
     45 
     46 import java.util.regex.Matcher;
     47 import java.util.regex.Pattern;
     48 import java.util.Random;
     49 
     50 /** Mister Widget appears on your home screen to provide helpful tips. */
     51 public class ProtipWidget extends AppWidgetProvider {
     52     public static final String ACTION_NEXT_TIP = "com.android.misterwidget.NEXT_TIP";
     53     public static final String ACTION_POKE = "com.android.misterwidget.HEE_HEE";
     54 
     55     public static final String EXTRA_TIMES = "times";
     56 
     57     public static final String PREFS_NAME = "Protips";
     58     public static final String PREFS_TIP_NUMBER = "widget_tip";
     59     public static final String PREFS_TIP_SET = "widget_tip_set";
     60 
     61     private static Random sRNG = new Random();
     62 
     63     private static final Pattern sNewlineRegex = Pattern.compile(" *\\n *");
     64     private static final Pattern sDrawableRegex = Pattern.compile(" *@(drawable/[a-z0-9_]+) *");
     65 
     66     // initial appearance: eyes closed, no bubble
     67     private int mIconRes = R.drawable.droidman_open;
     68     private int mMessage = 0;
     69     private int mTipSet = 0;
     70 
     71     private AppWidgetManager mWidgetManager = null;
     72     private int[] mWidgetIds;
     73     private Context mContext;
     74 
     75     private CharSequence[] mTips;
     76 
     77     private void setup(Context context) {
     78         mContext = context;
     79         mWidgetManager = AppWidgetManager.getInstance(context);
     80         mWidgetIds = mWidgetManager.getAppWidgetIds(new ComponentName(context, ProtipWidget.class));
     81 
     82         SharedPreferences pref = context.getSharedPreferences(PREFS_NAME, 0);
     83         mMessage = pref.getInt(PREFS_TIP_NUMBER, 0);
     84         mTipSet = pref.getInt(PREFS_TIP_SET, 0);
     85 
     86         mTips = context.getResources().getTextArray(mTipSet == 1 ? R.array.tips2 : R.array.tips);
     87 
     88         if (mTips != null) {
     89             if (mMessage >= mTips.length) mMessage = 0;
     90         } else {
     91             mMessage = -1;
     92         }
     93     }
     94 
     95     public void goodmorning() {
     96         mMessage = -1;
     97         try {
     98             setIcon(R.drawable.droidman_down_closed);
     99             Thread.sleep(500);
    100             setIcon(R.drawable.droidman_down_open);
    101             Thread.sleep(200);
    102             setIcon(R.drawable.droidman_down_closed);
    103             Thread.sleep(100);
    104             setIcon(R.drawable.droidman_down_open);
    105             Thread.sleep(600);
    106         } catch (InterruptedException ex) {
    107         }
    108         mMessage = 0;
    109         mIconRes = R.drawable.droidman_open;
    110         refresh();
    111     }
    112 
    113     @Override
    114     public void onReceive(Context context, Intent intent) {
    115         setup(context);
    116 
    117         Resources res = mContext.getResources();
    118         mTips = res.getTextArray(mTipSet == 1 ? R.array.tips2 : R.array.tips);
    119 
    120         if (intent.getAction().equals(ACTION_NEXT_TIP)) {
    121             mMessage = getNextMessageIndex();
    122             SharedPreferences.Editor pref = context.getSharedPreferences(PREFS_NAME, 0).edit();
    123             pref.putInt(PREFS_TIP_NUMBER, mMessage);
    124             pref.commit();
    125             refresh();
    126         } else if (intent.getAction().equals(ACTION_POKE)) {
    127             blink(intent.getIntExtra(EXTRA_TIMES, 1));
    128         } else if (intent.getAction().equals(AppWidgetManager.ACTION_APPWIDGET_ENABLED)) {
    129             goodmorning();
    130         } else if (intent.getAction().equals("android.provider.Telephony.SECRET_CODE")) {
    131             Log.d("Protips", "ACHIEVEMENT UNLOCKED");
    132             mTipSet = 1 - mTipSet;
    133             mMessage = 0;
    134 
    135             SharedPreferences.Editor pref = context.getSharedPreferences(PREFS_NAME, 0).edit();
    136             pref.putInt(PREFS_TIP_NUMBER, mMessage);
    137             pref.putInt(PREFS_TIP_SET, mTipSet);
    138             pref.commit();
    139 
    140             mContext.startActivity(
    141                 new Intent(Intent.ACTION_MAIN)
    142                     .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP)
    143                     .addCategory(Intent.CATEGORY_HOME));
    144 
    145             final Intent bcast = new Intent(context, ProtipWidget.class);
    146             bcast.setAction(ACTION_POKE);
    147             bcast.putExtra(EXTRA_TIMES, 3);
    148             mContext.sendBroadcast(bcast);
    149         } else {
    150             mIconRes = R.drawable.droidman_open;
    151             refresh();
    152         }
    153     }
    154 
    155     private void refresh() {
    156         RemoteViews rv = buildUpdate(mContext);
    157         for (int i : mWidgetIds) {
    158             mWidgetManager.updateAppWidget(i, rv);
    159         }
    160     }
    161 
    162     private void setIcon(int resId) {
    163         mIconRes = resId;
    164         refresh();
    165     }
    166 
    167     private int getNextMessageIndex() {
    168         return (mMessage + 1) % mTips.length;
    169     }
    170 
    171     private void blink(int blinks) {
    172         // don't blink if no bubble showing or if goodmorning() is happening
    173         if (mMessage < 0) return;
    174 
    175         setIcon(R.drawable.droidman_closed);
    176         try {
    177             Thread.sleep(100);
    178             while (0<--blinks) {
    179                 setIcon(R.drawable.droidman_open);
    180                 Thread.sleep(200);
    181                 setIcon(R.drawable.droidman_closed);
    182                 Thread.sleep(100);
    183             }
    184         } catch (InterruptedException ex) { }
    185         setIcon(R.drawable.droidman_open);
    186     }
    187 
    188     public RemoteViews buildUpdate(Context context) {
    189         RemoteViews updateViews = new RemoteViews(
    190             context.getPackageName(), R.layout.widget);
    191 
    192         // Action for tap on bubble
    193         Intent bcast = new Intent(context, ProtipWidget.class);
    194         bcast.setAction(ACTION_NEXT_TIP);
    195         PendingIntent pending = PendingIntent.getBroadcast(
    196             context, 0, bcast, PendingIntent.FLAG_UPDATE_CURRENT);
    197         updateViews.setOnClickPendingIntent(R.id.tip_bubble, pending);
    198 
    199         // Action for tap on android
    200         bcast = new Intent(context, ProtipWidget.class);
    201         bcast.setAction(ACTION_POKE);
    202         bcast.putExtra(EXTRA_TIMES, 1);
    203         pending = PendingIntent.getBroadcast(
    204             context, 0, bcast, PendingIntent.FLAG_UPDATE_CURRENT);
    205         updateViews.setOnClickPendingIntent(R.id.bugdroid, pending);
    206 
    207         // Tip bubble text
    208         if (mMessage >= 0) {
    209             String[] parts = sNewlineRegex.split(mTips[mMessage], 2);
    210             String title = parts[0];
    211             String text = parts.length > 1 ? parts[1] : "";
    212 
    213             // Look for a callout graphic referenced in the text
    214             Matcher m = sDrawableRegex.matcher(text);
    215             if (m.find()) {
    216                 String imageName = m.group(1);
    217                 int resId = context.getResources().getIdentifier(
    218 
    219                     imageName, null, context.getPackageName());
    220                 updateViews.setImageViewResource(R.id.tip_callout, resId);
    221                 updateViews.setViewVisibility(R.id.tip_callout, View.VISIBLE);
    222                 text = m.replaceFirst("");
    223             } else {
    224                 updateViews.setImageViewResource(R.id.tip_callout, 0);
    225                 updateViews.setViewVisibility(R.id.tip_callout, View.GONE);
    226             }
    227 
    228             updateViews.setTextViewText(R.id.tip_message,
    229                 text);
    230             updateViews.setTextViewText(R.id.tip_header,
    231                 title);
    232             updateViews.setTextViewText(R.id.tip_footer,
    233                 context.getResources().getString(
    234                     R.string.pager_footer,
    235                     (1+mMessage), mTips.length));
    236             updateViews.setViewVisibility(R.id.tip_bubble, View.VISIBLE);
    237         } else {
    238             updateViews.setViewVisibility(R.id.tip_bubble, View.INVISIBLE);
    239         }
    240 
    241         updateViews.setImageViewResource(R.id.bugdroid, mIconRes);
    242 
    243         return updateViews;
    244     }
    245 }
    246