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
17package com.android.settings;
18
19import android.app.Activity;
20import android.app.AlertDialog;
21import android.app.Dialog;
22import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.DialogInterface;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.os.Bundle;
28import android.util.Log;
29import android.view.LayoutInflater;
30import android.view.Menu;
31import android.view.MenuInflater;
32import android.view.MenuItem;
33import android.view.MenuItem.OnMenuItemClickListener;
34import android.view.MotionEvent;
35import android.view.View;
36import android.view.View.OnClickListener;
37import android.view.View.OnTouchListener;
38import android.view.ViewGroup;
39import android.widget.ArrayAdapter;
40import android.widget.ImageView;
41import android.widget.ListView;
42import android.widget.RadioButton;
43import android.widget.Switch;
44import android.widget.TextView;
45
46import com.android.settings.DreamBackend.DreamInfo;
47import com.android.settings.widget.SwitchBar;
48
49import java.util.List;
50
51public 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
68    public int getHelpResource() {
69        return R.string.help_url_dreams;
70    }
71
72    @Override
73    public void onAttach(Activity activity) {
74        logd("onAttach(%s)", activity.getClass().getSimpleName());
75        super.onAttach(activity);
76        mContext = activity;
77    }
78
79    @Override
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
90    public void onSwitchChanged(Switch switchView, boolean isChecked) {
91        if (!mRefreshing) {
92            mBackend.setEnabled(isChecked);
93            refreshFromBackend();
94        }
95    }
96
97    @Override
98    public void onStart() {
99        logd("onStart()");
100        super.onStart();
101    }
102
103    @Override
104    public void onDestroyView() {
105        logd("onDestroyView()");
106        super.onDestroyView();
107
108        mSwitchBar.removeOnSwitchChangeListener(this);
109        mSwitchBar.hide();
110    }
111
112    @Override
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
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
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
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
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