• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.camera;
2 
3 import com.android.gallery.R;
4 
5 import android.content.Context;
6 import android.graphics.PixelFormat;
7 import android.os.Handler;
8 import android.os.Message;
9 import android.preference.ListPreference;
10 import android.preference.Preference;
11 import android.preference.PreferenceGroup;
12 import android.preference.PreferenceScreen;
13 import android.view.animation.Animation;
14 import android.view.animation.Animation.AnimationListener;
15 import android.view.Display;
16 import android.view.Gravity;
17 import android.view.KeyEvent;
18 import android.view.LayoutInflater;
19 import android.view.MotionEvent;
20 import android.view.View;
21 import android.view.ViewGroup;
22 import android.view.WindowManager;
23 import android.view.WindowManager.LayoutParams;
24 import android.widget.AdapterView;
25 import android.widget.BaseAdapter;
26 import android.widget.FrameLayout;
27 import android.widget.ImageView;
28 import android.widget.ListView;
29 import android.widget.RadioButton;
30 import android.widget.TextView;
31 import android.widget.AdapterView.OnItemClickListener;
32 
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 
36 // Please reference to {@link android.widget.ZoomButtonsController} for detail
37 // information about adding window to WindowManager.
38 public class OnScreenSettings {
39     @SuppressWarnings("unused")
40     private static final String TAG = "OnScreenSettings";
41     private static final int MSG_POST_SET_VISIBLE = 1;
42 
43     public interface OnVisibilityChangedListener {
onVisibilityChanged(boolean visibility)44         public void onVisibilityChanged(boolean visibility);
45     }
46 
47     private LayoutParams mContainerLayoutParams;
48     private final Context mContext;
49     private final Container mContainer;
50     private final WindowManager mWindowManager;
51     private final View mOwnerView;
52     private ListView mMainMenu;
53     private ListView mSubMenu;
54     private View mMainPanel;
55     private boolean mIsVisible = false;
56     private OnVisibilityChangedListener mVisibilityListener;
57     private MainMenuAdapter mMainAdapter;
58 
59     private final LayoutInflater mInflater;
60 
61     // We store the override values here. For a given preference,
62     // if the mapping value of the preference key is not null, we will
63     // use the value in this map instead of the value read from the preference
64     //
65     // This is design for the scene mode, for example, in the scene mode
66     // "Action", the focus mode will become "infinite" no matter what in the
67     // preference settings. So, we need to put a {pref_camera_focusmode_key,
68     // "infinite"} entry in this map.
69     private HashMap<String, String> mOverride = new HashMap<String, String>();
70 
71     private final Handler mHandler = new Handler() {
72         @Override
73         public void handleMessage(Message msg) {
74             switch (msg.what) {
75                 case MSG_POST_SET_VISIBLE:
76                     setVisible(true);
77                     break;
78             }
79         }
80     };
81 
OnScreenSettings(View ownerView)82     public OnScreenSettings(View ownerView) {
83         mContext = ownerView.getContext();
84         mInflater = (LayoutInflater)
85                 mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
86 
87         mWindowManager = (WindowManager)
88                 mContext.getSystemService(Context.WINDOW_SERVICE);
89         mOwnerView = ownerView;
90         mContainer = createContainer();
91     }
92 
isVisible()93     public boolean isVisible() {
94         return mIsVisible;
95     }
96 
setOnVisibilityChangedListener( OnVisibilityChangedListener listener)97     public void setOnVisibilityChangedListener(
98             OnVisibilityChangedListener listener) {
99         mVisibilityListener = listener;
100     }
101 
setVisible(boolean visible)102     public void setVisible(boolean visible) {
103         mHandler.removeMessages(MSG_POST_SET_VISIBLE);
104         if (visible) {
105             if (mOwnerView.getWindowToken() == null) {
106                 /*
107                  * We need a window token to show ourselves, maybe the owner's
108                  * window hasn't been created yet but it will have been by the
109                  * time the looper is idle, so post the setVisible(true) call.
110                  */
111                 mHandler.sendEmptyMessage(MSG_POST_SET_VISIBLE);
112                 return;
113             }
114         }
115 
116         if (mIsVisible == visible) {
117             return;
118         }
119         mIsVisible = visible;
120 
121         if (visible) {
122             // Update main adapter before show up
123             if (mMainAdapter != null) mMainAdapter.notifyDataSetChanged();
124             if (mContainerLayoutParams.token == null) {
125                 mContainerLayoutParams.token = mOwnerView.getWindowToken();
126             }
127             mSubMenu.setVisibility(View.INVISIBLE);
128             mMainMenu.setVisibility(View.VISIBLE);
129             mWindowManager.addView(mContainer, mContainerLayoutParams);
130             updateLayout();
131         } else {
132             // Reset the two menus
133 
134             mWindowManager.removeView(mContainer);
135         }
136         if (mVisibilityListener != null) {
137             mVisibilityListener.onVisibilityChanged(mIsVisible);
138         }
139     }
140 
141     // Override the preference settings, if value == null, then disable the
142     // override.
overrideSettings(String key, String value)143     public void overrideSettings(String key, String value) {
144         if (value == null) {
145             if (mOverride.remove(key) != null && mMainAdapter != null) {
146                 mMainAdapter.notifyDataSetChanged();
147             }
148         } else {
149             if (mOverride.put(key, value) == null && mMainAdapter != null) {
150                 mMainAdapter.notifyDataSetChanged();
151             }
152         }
153     }
154 
updateLayout()155     public void updateLayout() {
156         // if the mOwnerView is detached from window then skip.
157         if (mOwnerView.getWindowToken() == null) return;
158         Display display = mWindowManager.getDefaultDisplay();
159 
160         mContainerLayoutParams.x = 0;
161         mContainerLayoutParams.y = 0;
162 
163         mContainerLayoutParams.width = display.getWidth() / 2;
164         mContainerLayoutParams.height = display.getHeight();
165 
166         if (mIsVisible) {
167             mWindowManager.updateViewLayout(mContainer, mContainerLayoutParams);
168         }
169     }
170 
showSubMenu()171     private void showSubMenu() {
172         Util.slideOut(mMainMenu, Util.DIRECTION_LEFT);
173         Util.slideIn(mSubMenu, Util.DIRECTION_RIGHT);
174         mSubMenu.requestFocus();
175     }
176 
closeSubMenu()177     private void closeSubMenu() {
178         Util.slideOut(mSubMenu, Util.DIRECTION_RIGHT);
179         Util.slideIn(mMainMenu, Util.DIRECTION_LEFT);
180     }
181 
createContainer()182     private Container createContainer() {
183         LayoutParams lp = new LayoutParams(
184                 LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
185         lp.flags = LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
186         lp.gravity = Gravity.TOP | Gravity.LEFT;
187         lp.height = LayoutParams.WRAP_CONTENT;
188         lp.width = LayoutParams.WRAP_CONTENT;
189         lp.type = LayoutParams.TYPE_APPLICATION_PANEL;
190         lp.format = PixelFormat.OPAQUE;
191         lp.windowAnimations = R.style.Animation_OnScreenMenu;
192 
193         mContainerLayoutParams = lp;
194 
195         Container container = new Container(mContext);
196         container.setLayoutParams(lp);
197 
198         mInflater.inflate(R.layout.on_screen_menu, container);
199 
200         mMainPanel = container.findViewById(R.id.main_panel);
201         mMainMenu = (ListView) container.findViewById(R.id.menu_view);
202         mSubMenu = (ListView) container.findViewById(R.id.sub_menu);
203 
204         container.findViewById(R.id.btn_gripper)
205                 .setOnTouchListener(new GripperTouchListener());
206 
207         return container;
208     }
209 
210     private class GripperTouchListener implements View.OnTouchListener {
onTouch(View view, MotionEvent event)211         public boolean onTouch(View view, MotionEvent event) {
212             switch (event.getAction()) {
213                 case MotionEvent.ACTION_DOWN:
214                     return true;
215                 case MotionEvent.ACTION_UP:
216                     setVisible(false);
217                     return true;
218             }
219             return false;
220         }
221     }
222 
onContainerKey(KeyEvent event)223     private boolean onContainerKey(KeyEvent event) {
224         switch (event.getKeyCode()) {
225             case KeyEvent.KEYCODE_CAMERA:
226             case KeyEvent.KEYCODE_FOCUS:
227             case KeyEvent.KEYCODE_BACK:
228             case KeyEvent.KEYCODE_MENU:
229                 if (event.getAction() == KeyEvent.ACTION_UP) {
230                     setVisible(false);
231                     return true;
232                 }
233         }
234         return false;
235     }
236 
237     // Add the preference and it's children recursively to the given list. So
238     // that we can show the preference (and it's children) in the list view.
addPreference( Preference preference, ArrayList<Preference> list)239     private static void addPreference(
240             Preference preference, ArrayList<Preference> list) {
241         list.add(preference);
242         if (preference instanceof PreferenceGroup) {
243             PreferenceGroup group = (PreferenceGroup) preference;
244             for (int i = 0, n = group.getPreferenceCount(); i < n; ++i) {
245                 Preference child = group.getPreference(i);
246                 addPreference(child, list);
247             }
248         }
249     }
250 
setPreferenceScreen(PreferenceScreen screen)251     public void setPreferenceScreen(PreferenceScreen screen) {
252         ArrayList<Preference> list = new ArrayList<Preference>();
253 
254         // We don't want the screen add to the list, we add the first level
255         // preference here.
256         for (int  i = 0, n = screen.getPreferenceCount(); i < n; ++i) {
257             addPreference(screen.getPreference(i), list);
258         }
259         mMainAdapter = new MainMenuAdapter(mContext, list);
260         mMainMenu.setAdapter(mMainAdapter);
261         mMainMenu.setOnItemClickListener(mMainAdapter);
262     }
263 
inflateIfNeed( View view, int resource, ViewGroup root, boolean attachToRoot)264     private View inflateIfNeed(
265             View view, int resource, ViewGroup root, boolean attachToRoot) {
266         if (view != null) return view;
267         return mInflater.inflate(resource, root, attachToRoot);
268     }
269 
270     private class MainMenuAdapter extends BaseAdapter
271             implements OnItemClickListener {
272         private final ArrayList<Preference> mPreferences;
273 
MainMenuAdapter( Context context, ArrayList<Preference> preferences)274         public MainMenuAdapter(
275                 Context context, ArrayList<Preference> preferences) {
276             mPreferences = preferences;
277         }
278 
onItemClick( AdapterView<?> parent, View view, int position, long id)279         public void onItemClick(
280                 AdapterView<?> parent, View view, int position, long id) {
281             Preference preference = mPreferences.get(position);
282             SubMenuAdapter adapter = new SubMenuAdapter(
283                     mContext, (ListPreference) preference);
284             mSubMenu.setAdapter(adapter);
285             mSubMenu.setOnItemClickListener(adapter);
286             showSubMenu();
287         }
288 
getView(int position, View convertView, ViewGroup parent)289         public View getView(int position, View convertView, ViewGroup parent) {
290             Preference preference = mPreferences.get(position);
291 
292             if (preference instanceof PreferenceGroup) {
293                 convertView = inflateIfNeed(convertView,
294                         R.layout.on_screen_menu_header, parent, false);
295                 PreferenceGroup group = (PreferenceGroup) preference;
296                 ((TextView) convertView.findViewById(
297                         R.id.title)).setText(group.getTitle());
298             } else {
299                 convertView = inflateIfNeed(convertView,
300                         R.layout.on_screen_menu_list_item, parent, false);
301 
302                 String override = mOverride.get(preference.getKey());
303                 TextView title = (TextView)
304                         convertView.findViewById(R.id.title);
305                 title.setText(preference.getTitle());
306                 title.setEnabled(override == null);
307 
308                 TextView summary = (TextView)
309                         convertView.findViewById(R.id.summary);
310                 summary.setText(override == null
311                         ? ((ListPreference) preference).getEntry()
312                         : override);
313                 summary.setEnabled(override == null);
314 
315                 // A little trick here, making the view focusable will eat
316                 // both touch/key events on the view and thus make it looks
317                 // like disabled.
318                 convertView.setFocusable(override != null);
319             }
320             return convertView;
321         }
322 
323         @Override
areAllItemsEnabled()324         public boolean areAllItemsEnabled() {
325             return false;
326         }
327 
328         @Override
isEnabled(int position)329         public boolean isEnabled(int position) {
330             Preference preference = mPreferences.get(position);
331             return !(preference instanceof PreferenceGroup);
332         }
333 
getCount()334         public int getCount() {
335             return mPreferences.size();
336         }
337 
getItem(int position)338         public Object getItem(int position) {
339             return null;
340         }
341 
getItemId(int position)342         public long getItemId(int position) {
343             return position;
344         }
345 
346         @Override
getItemViewType(int position)347         public int getItemViewType(int position) {
348             Preference pref = mPreferences.get(position);
349             if (pref instanceof PreferenceGroup) return 0;
350             if (pref instanceof ListPreference) return 1;
351             throw new IllegalStateException();
352         }
353 
354         @Override
getViewTypeCount()355         public int getViewTypeCount() {
356             // we have two types, see getItemViewType()
357             return 2;
358         }
359 
360         @Override
hasStableIds()361         public boolean hasStableIds() {
362             return true;
363         }
364 
365         @Override
isEmpty()366         public boolean isEmpty() {
367             return mPreferences.isEmpty();
368         }
369     }
370 
371     private class SubMenuAdapter extends BaseAdapter
372             implements OnItemClickListener {
373         private final ListPreference mPreference;
374         private final IconListPreference mIconPreference;
375 
SubMenuAdapter(Context context, ListPreference preference)376         public SubMenuAdapter(Context context, ListPreference preference) {
377             mPreference = preference;
378             mIconPreference = (preference instanceof IconListPreference)
379                     ? (IconListPreference) preference
380                     : null;
381         }
382 
getView(int position, View convertView, ViewGroup parent)383         public View getView(int position, View convertView, ViewGroup parent) {
384             CharSequence entry[] = mPreference.getEntries();
385             if (position == 0) {
386                 convertView = inflateIfNeed(convertView,
387                         R.layout.on_screen_menu_header, parent, false);
388                 ((TextView) convertView.findViewById(
389                         R.id.title)).setText(mPreference.getDialogTitle());
390             } else {
391                 int index = position - 1;
392                 convertView = inflateIfNeed(convertView,
393                         R.layout.on_screen_submenu_item, parent, false);
394                 boolean checked = mPreference.getValue().equals(
395                         mPreference.getEntryValues()[index]);
396                 ((TextView) convertView.findViewById(
397                         R.id.title)).setText(entry[index]);
398                 ((RadioButton) convertView.findViewById(
399                         R.id.radio_button)).setChecked(checked);
400                 ImageView icon = (ImageView)
401                         convertView.findViewById(R.id.icon);
402                 if (mIconPreference != null) {
403                     icon.setVisibility(View.VISIBLE);
404                     icon.setImageDrawable(
405                             mIconPreference.getIcons()[position-1]);
406                 } else {
407                     icon.setVisibility(View.GONE);
408                 }
409             }
410             return convertView;
411         }
412 
413         @Override
areAllItemsEnabled()414         public boolean areAllItemsEnabled() {
415             return false;
416         }
417 
418         @Override
isEnabled(int position)419         public boolean isEnabled(int position) {
420             return getItemViewType(position) != 0;
421         }
422 
getCount()423         public int getCount() {
424             // add one for the header
425             return mPreference.getEntries().length + 1;
426         }
427 
getItem(int position)428         public Object getItem(int position) {
429             return null;
430         }
431 
getItemId(int position)432         public long getItemId(int position) {
433             return position;
434         }
435 
436         @Override
getItemViewType(int position)437         public int getItemViewType(int position) {
438             return position == 0 ? 0 : 1;
439         }
440 
441         @Override
getViewTypeCount()442         public int getViewTypeCount() {
443             return 2;
444         }
445 
446         @Override
hasStableIds()447         public boolean hasStableIds() {
448             return true;
449         }
450 
onItemClick( AdapterView<?> parent, View view, int position, long id)451         public void onItemClick(
452                 AdapterView<?> parent, View view, int position, long id) {
453             CharSequence values[] = mPreference.getEntryValues();
454             int idx = mPreference.findIndexOfValue(mPreference.getValue());
455             if (idx != position - 1) {
456                 mPreference.setValueIndex(position - 1);
457                 notifyDataSetChanged();
458                 mMainAdapter.notifyDataSetChanged();
459                 return;
460             }
461 
462             // Close the sub menu when user presses the original option.
463             closeSubMenu();
464         }
465     }
466 
467     private class Container extends FrameLayout {
Container(Context context)468         public Container(Context context) {
469             super(context);
470         }
471 
472         @Override
onTouchEvent(MotionEvent event)473         public boolean onTouchEvent(MotionEvent event) {
474             if (super.onTouchEvent(event)) return true;
475             if (event.getAction() == MotionEvent.ACTION_DOWN) {
476                 setVisible(false);
477                 return true;
478             }
479             return false;
480         }
481 
482         /*
483          * Need to override this to intercept the key events. Otherwise, we
484          * would attach a key listener to the container but its superclass
485          * ViewGroup gives it to the focused View instead of calling the key
486          * listener, and so we wouldn't get the events.
487          */
488         @Override
dispatchKeyEvent(KeyEvent event)489         public boolean dispatchKeyEvent(KeyEvent event) {
490             return onContainerKey(event)
491                     ? true
492                     : super.dispatchKeyEvent(event);
493         }
494     }
495 }
496