• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
setup(Context context)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 
goodmorning()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
onReceive(Context context, Intent intent)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 
refresh()155     private void refresh() {
156         RemoteViews rv = buildUpdate(mContext);
157         for (int i : mWidgetIds) {
158             mWidgetManager.updateAppWidget(i, rv);
159         }
160     }
161 
setIcon(int resId)162     private void setIcon(int resId) {
163         mIconRes = resId;
164         refresh();
165     }
166 
getNextMessageIndex()167     private int getNextMessageIndex() {
168         return (mMessage + 1) % mTips.length;
169     }
170 
blink(int blinks)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 
buildUpdate(Context context)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