1 /*
2  * Copyright (C) 2012 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.settings;
18 
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.app.Dialog;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.os.Bundle;
28 import android.util.Log;
29 import android.view.LayoutInflater;
30 import android.view.Menu;
31 import android.view.MenuInflater;
32 import android.view.MenuItem;
33 import android.view.MenuItem.OnMenuItemClickListener;
34 import android.view.MotionEvent;
35 import android.view.View;
36 import android.view.View.OnClickListener;
37 import android.view.View.OnTouchListener;
38 import android.view.ViewGroup;
39 import android.widget.ArrayAdapter;
40 import android.widget.ImageView;
41 import android.widget.ListView;
42 import android.widget.RadioButton;
43 import android.widget.Switch;
44 import android.widget.TextView;
45 
46 import com.android.settings.DreamBackend.DreamInfo;
47 import com.android.settings.widget.SwitchBar;
48 
49 import java.util.List;
50 
51 public class DreamSettings extends SettingsPreferenceFragment implements
52         SwitchBar.OnSwitchChangeListener {
53     private static final String TAG = DreamSettings.class.getSimpleName();
54     static final boolean DEBUG = false;
55     private static final int DIALOG_WHEN_TO_DREAM = 1;
56     private static final String PACKAGE_SCHEME = "package";
57 
58     private final PackageReceiver mPackageReceiver = new PackageReceiver();
59 
60     private Context mContext;
61     private DreamBackend mBackend;
62     private DreamInfoAdapter mAdapter;
63     private SwitchBar mSwitchBar;
64     private MenuItem[] mMenuItemsWhenEnabled;
65     private boolean mRefreshing;
66 
67     @Override
getHelpResource()68     public int getHelpResource() {
69         return R.string.help_url_dreams;
70     }
71 
72     @Override
onAttach(Activity activity)73     public void onAttach(Activity activity) {
74         logd("onAttach(%s)", activity.getClass().getSimpleName());
75         super.onAttach(activity);
76         mContext = activity;
77     }
78 
79     @Override
onCreate(Bundle icicle)80     public void onCreate(Bundle icicle) {
81         logd("onCreate(%s)", icicle);
82         super.onCreate(icicle);
83 
84         mBackend = new DreamBackend(getActivity());
85 
86         setHasOptionsMenu(true);
87     }
88 
89     @Override
onSwitchChanged(Switch switchView, boolean isChecked)90     public void onSwitchChanged(Switch switchView, boolean isChecked) {
91         if (!mRefreshing) {
92             mBackend.setEnabled(isChecked);
93             refreshFromBackend();
94         }
95     }
96 
97     @Override
onStart()98     public void onStart() {
99         logd("onStart()");
100         super.onStart();
101     }
102 
103     @Override
onDestroyView()104     public void onDestroyView() {
105         logd("onDestroyView()");
106         super.onDestroyView();
107 
108         mSwitchBar.removeOnSwitchChangeListener(this);
109         mSwitchBar.hide();
110     }
111 
112     @Override
onActivityCreated(Bundle savedInstanceState)113     public void onActivityCreated(Bundle savedInstanceState) {
114         logd("onActivityCreated(%s)", savedInstanceState);
115         super.onActivityCreated(savedInstanceState);
116 
117         ListView listView = getListView();
118         listView.setItemsCanFocus(true);
119 
120         TextView emptyView = (TextView) getView().findViewById(android.R.id.empty);
121         emptyView.setText(R.string.screensaver_settings_disabled_prompt);
122         listView.setEmptyView(emptyView);
123 
124         mAdapter = new DreamInfoAdapter(mContext);
125         listView.setAdapter(mAdapter);
126 
127         final SettingsActivity sa = (SettingsActivity) getActivity();
128         mSwitchBar = sa.getSwitchBar();
129         mSwitchBar.addOnSwitchChangeListener(this);
130         mSwitchBar.show();
131     }
132 
133     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)134     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
135         logd("onCreateOptionsMenu()");
136 
137         boolean isEnabled = mBackend.isEnabled();
138 
139         // create "start" action
140         MenuItem start = createMenuItem(menu, R.string.screensaver_settings_dream_start,
141                 MenuItem.SHOW_AS_ACTION_NEVER,
142                 isEnabled, new Runnable(){
143                     @Override
144                     public void run() {
145                         mBackend.startDreaming();
146                     }});
147 
148         // create "when to dream" overflow menu item
149         MenuItem whenToDream = createMenuItem(menu,
150                 R.string.screensaver_settings_when_to_dream,
151                 MenuItem.SHOW_AS_ACTION_NEVER,
152                 isEnabled,
153                 new Runnable() {
154                     @Override
155                     public void run() {
156                         showDialog(DIALOG_WHEN_TO_DREAM);
157                     }});
158 
159         // create "help" overflow menu item (make sure it appears last)
160         super.onCreateOptionsMenu(menu, inflater);
161 
162         mMenuItemsWhenEnabled = new MenuItem[] { start, whenToDream };
163     }
164 
createMenuItem(Menu menu, int titleRes, int actionEnum, boolean isEnabled, final Runnable onClick)165     private MenuItem createMenuItem(Menu menu,
166             int titleRes, int actionEnum, boolean isEnabled, final Runnable onClick) {
167         MenuItem item = menu.add(titleRes);
168         item.setShowAsAction(actionEnum);
169         item.setEnabled(isEnabled);
170         item.setOnMenuItemClickListener(new OnMenuItemClickListener() {
171             @Override
172             public boolean onMenuItemClick(MenuItem item) {
173                 onClick.run();
174                 return true;
175             }
176         });
177         return item;
178     }
179 
180     @Override
onCreateDialog(int dialogId)181     public Dialog onCreateDialog(int dialogId) {
182         logd("onCreateDialog(%s)", dialogId);
183         if (dialogId == DIALOG_WHEN_TO_DREAM)
184             return createWhenToDreamDialog();
185         return super.onCreateDialog(dialogId);
186     }
187 
createWhenToDreamDialog()188     private Dialog createWhenToDreamDialog() {
189         final CharSequence[] items = {
190                 mContext.getString(R.string.screensaver_settings_summary_dock),
191                 mContext.getString(R.string.screensaver_settings_summary_sleep),
192                 mContext.getString(R.string.screensaver_settings_summary_either_short)
193         };
194 
195         int initialSelection = mBackend.isActivatedOnDock() && mBackend.isActivatedOnSleep() ? 2
196                 : mBackend.isActivatedOnDock() ? 0
197                 : mBackend.isActivatedOnSleep() ? 1
198                 : -1;
199 
200         return new AlertDialog.Builder(mContext)
201                 .setTitle(R.string.screensaver_settings_when_to_dream)
202                 .setSingleChoiceItems(items, initialSelection, new DialogInterface.OnClickListener() {
203                     public void onClick(DialogInterface dialog, int item) {
204                         mBackend.setActivatedOnDock(item == 0 || item == 2);
205                         mBackend.setActivatedOnSleep(item == 1 || item == 2);
206                         dialog.dismiss();
207                     }
208                 })
209                 .create();
210     }
211 
212     @Override
213     public void onPause() {
214         logd("onPause()");
215         super.onPause();
216 
217         mContext.unregisterReceiver(mPackageReceiver);
218     }
219 
220     @Override
221     public void onResume() {
222         logd("onResume()");
223         super.onResume();
224         refreshFromBackend();
225 
226         // listen for package changes
227         IntentFilter filter = new IntentFilter();
228         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
229         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
230         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
231         filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
232         filter.addDataScheme(PACKAGE_SCHEME);
233         mContext.registerReceiver(mPackageReceiver , filter);
234     }
235 
236     public static int getSummaryResource(Context context) {
237         DreamBackend backend = new DreamBackend(context);
238         boolean isEnabled = backend.isEnabled();
239         boolean activatedOnSleep = backend.isActivatedOnSleep();
240         boolean activatedOnDock = backend.isActivatedOnDock();
241         boolean activatedOnEither = activatedOnSleep && activatedOnDock;
242         return !isEnabled ? R.string.screensaver_settings_summary_off
243                 : activatedOnEither ? R.string.screensaver_settings_summary_either_long
244                 : activatedOnSleep ? R.string.screensaver_settings_summary_sleep
245                 : activatedOnDock ? R.string.screensaver_settings_summary_dock
246                 : 0;
247     }
248 
249     public static CharSequence getSummaryTextWithDreamName(Context context) {
250         DreamBackend backend = new DreamBackend(context);
251         boolean isEnabled = backend.isEnabled();
252         if (!isEnabled) {
253             return context.getString(R.string.screensaver_settings_summary_off);
254         } else {
255             return backend.getActiveDreamName();
256         }
257     }
258 
259     private void refreshFromBackend() {
260         logd("refreshFromBackend()");
261         mRefreshing = true;
262         boolean dreamsEnabled = mBackend.isEnabled();
263         if (mSwitchBar.isChecked() != dreamsEnabled)
264             mSwitchBar.setChecked(dreamsEnabled);
265 
266         mAdapter.clear();
267         if (dreamsEnabled) {
268             List<DreamInfo> dreamInfos = mBackend.getDreamInfos();
269             mAdapter.addAll(dreamInfos);
270         }
271         if (mMenuItemsWhenEnabled != null)
272             for (MenuItem menuItem : mMenuItemsWhenEnabled)
273                 menuItem.setEnabled(dreamsEnabled);
274         mRefreshing = false;
275     }
276 
277     private static void logd(String msg, Object... args) {
278         if (DEBUG)
279             Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args));
280     }
281 
282     private class DreamInfoAdapter extends ArrayAdapter<DreamInfo> {
283         private final LayoutInflater mInflater;
284 
285         public DreamInfoAdapter(Context context) {
286             super(context, 0);
287             mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
288         }
289 
290         @Override
291         public View getView(int position, View convertView, ViewGroup parent) {
292             DreamInfo dreamInfo = getItem(position);
293             logd("getView(%s)", dreamInfo.caption);
294             final View row = convertView != null ? convertView : createDreamInfoRow(parent);
295             row.setTag(dreamInfo);
296 
297             // bind icon
298             ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(dreamInfo.icon);
299 
300             // bind caption
301             ((TextView) row.findViewById(android.R.id.title)).setText(dreamInfo.caption);
302 
303             // bind radio button
304             RadioButton radioButton = (RadioButton) row.findViewById(android.R.id.button1);
305             radioButton.setChecked(dreamInfo.isActive);
306             radioButton.setOnTouchListener(new OnTouchListener() {
307                 @Override
308                 public boolean onTouch(View v, MotionEvent event) {
309                     row.onTouchEvent(event);
310                     return false;
311                 }});
312 
313             // bind settings button + divider
314             boolean showSettings = dreamInfo.settingsComponentName != null;
315             View settingsDivider = row.findViewById(R.id.divider);
316             settingsDivider.setVisibility(showSettings ? View.VISIBLE : View.INVISIBLE);
317 
318             ImageView settingsButton = (ImageView) row.findViewById(android.R.id.button2);
319             settingsButton.setVisibility(showSettings ? View.VISIBLE : View.INVISIBLE);
320             settingsButton.setAlpha(dreamInfo.isActive ? 1f : Utils.DISABLED_ALPHA);
321             settingsButton.setEnabled(dreamInfo.isActive);
322             settingsButton.setFocusable(dreamInfo.isActive);
323             settingsButton.setOnClickListener(new OnClickListener(){
324                 @Override
325                 public void onClick(View v) {
326                     mBackend.launchSettings((DreamInfo) row.getTag());
327                 }});
328 
329             return row;
330         }
331 
332         private View createDreamInfoRow(ViewGroup parent) {
333             final View row =  mInflater.inflate(R.layout.dream_info_row, parent, false);
334             final View header = row.findViewById(android.R.id.widget_frame);
335             header.setOnClickListener(new OnClickListener(){
336                 @Override
337                 public void onClick(View v) {
338                     v.setPressed(true);
339                     activate((DreamInfo) row.getTag());
340                 }});
341             return row;
342         }
343 
344         private DreamInfo getCurrentSelection() {
345             for (int i = 0; i < getCount(); i++) {
346                 DreamInfo dreamInfo = getItem(i);
347                 if (dreamInfo.isActive)
348                     return dreamInfo;
349             }
350             return null;
351         }
352         private void activate(DreamInfo dreamInfo) {
353             if (dreamInfo.equals(getCurrentSelection()))
354                 return;
355             for (int i = 0; i < getCount(); i++) {
356                 getItem(i).isActive = false;
357             }
358             dreamInfo.isActive = true;
359             mBackend.setActiveDream(dreamInfo.componentName);
360             notifyDataSetChanged();
361         }
362     }
363 
364     private class PackageReceiver extends BroadcastReceiver {
365         @Override
366         public void onReceive(Context context, Intent intent) {
367             logd("PackageReceiver.onReceive");
368             refreshFromBackend();
369         }
370     }
371 }
372