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