779aa4639b514490cfab01f7afb668c5e9324d18
[iec.git] / src / type3_AndroidCloud / anbox-master / android / appmgr / src / org / anbox / appmgr / GridFragment.java
1 package org.anbox.appmgr;
2
3 /*
4  * Created by Thomas Barrasso on 9/11/12.
5  * Copyright (c) 2012 Loupe Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import android.content.Context;
21 import android.content.res.Resources;
22 import android.os.Build;
23 import android.os.Bundle;
24 import android.os.Handler;
25 import android.support.v4.app.Fragment;
26 import android.util.TypedValue;
27 import android.view.Gravity;
28 import android.view.LayoutInflater;
29 import android.view.View;
30 import android.view.ViewGroup;
31 import android.view.animation.AnimationUtils;
32 import android.widget.AdapterView;
33 import android.widget.FrameLayout;
34 import android.widget.GridView;
35 import android.widget.LinearLayout;
36 import android.widget.ListAdapter;
37 import android.widget.ListView;
38 import android.widget.ProgressBar;
39 import android.widget.TextView;
40
41 /**
42  * Based on {@link android.app.ListFragment} but adapted for {@link GridView}.
43  */
44 public class GridFragment extends Fragment {
45
46     static final int INTERNAL_EMPTY_ID = 0x00ff0001;
47     static final int INTERNAL_PROGRESS_CONTAINER_ID = 0x00ff0002;
48     static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003;
49
50     final private Handler mHandler = new Handler();
51
52     final private Runnable mRequestFocus = new Runnable() {
53         public void run() {
54             mGrid.focusableViewAvailable(mGrid);
55         }
56     };
57
58     final private AdapterView.OnItemClickListener mOnClickListener
59             = new AdapterView.OnItemClickListener() {
60         public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
61             onGridItemClick((GridView) parent, v, position, id);
62         }
63     };
64
65     ListAdapter mAdapter;
66     GridView mGrid;
67     View mEmptyView;
68     TextView mStandardEmptyView;
69     View mProgressContainer;
70     View mGridContainer;
71     CharSequence mEmptyText;
72     boolean mGridShown;
73
74     public GridFragment() { }
75
76     /**
77      * Provide default implementation to return a simple grid view.  Subclasses
78      * can override to replace with their own layout.  If doing so, the
79      * returned view hierarchy <em>must</em> have a GridView whose id
80      * is {@link android.R.id#list android.R.id.list} and can optionally
81      * have a sibling view id {@link android.R.id#empty android.R.id.empty}
82      * that is to be shown when the grid is empty.
83      *
84      * <p>If you are overriding this method with your own custom content,
85      * consider including the standard layout {@link android.R.layout#list_content}
86      * in your layout file, so that you continue to retain all of the standard
87      * behavior of ListFragment.  In particular, this is currently the only
88      * way to have the built-in indeterminant progress state be shown.
89      */
90     @Override
91     public View onCreateView(LayoutInflater inflater, ViewGroup container,
92                              Bundle savedInstanceState) {
93         final Context context = getActivity();
94
95         FrameLayout root = new FrameLayout(context);
96
97         // ------------------------------------------------------------------
98
99         LinearLayout pframe = new LinearLayout(context);
100         pframe.setId(INTERNAL_PROGRESS_CONTAINER_ID);
101         pframe.setOrientation(LinearLayout.VERTICAL);
102         pframe.setVisibility(View.GONE);
103         pframe.setGravity(Gravity.CENTER);
104
105         ProgressBar progress = new ProgressBar(context, null,
106                 android.R.attr.progressBarStyleLarge);
107         pframe.addView(progress, new FrameLayout.LayoutParams(
108                 ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
109
110         root.addView(pframe, new FrameLayout.LayoutParams(
111                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
112
113         // ------------------------------------------------------------------
114
115         FrameLayout lframe = new FrameLayout(context);
116         lframe.setId(INTERNAL_LIST_CONTAINER_ID);
117
118         TextView tv = new TextView(getActivity());
119         tv.setId(INTERNAL_EMPTY_ID);
120         tv.setGravity(Gravity.CENTER);
121         lframe.addView(tv, new FrameLayout.LayoutParams(
122                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
123
124         GridView lv = new GridView(getActivity());
125         lv.setId(android.R.id.list);
126         lv.setDrawSelectorOnTop(false);
127         lv.setColumnWidth(convertDpToPixels(60, getActivity()));
128         lv.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
129         lv.setNumColumns(GridView.AUTO_FIT);
130         lv.setHorizontalSpacing(convertDpToPixels(20, getActivity()));
131         lv.setVerticalSpacing(convertDpToPixels(20, getActivity()));
132         lv.setSmoothScrollbarEnabled(true);
133
134         // disable overscroll
135         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
136             lv.setOverScrollMode(ListView.OVER_SCROLL_NEVER);
137         }
138
139         lframe.addView(lv, new FrameLayout.LayoutParams(
140                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
141
142         root.addView(lframe, new FrameLayout.LayoutParams(
143                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
144
145         // ------------------------------------------------------------------
146
147         root.setLayoutParams(new FrameLayout.LayoutParams(
148                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
149
150         return root;
151     }
152
153     /**
154      * Attach to grid view once the view hierarchy has been created.
155      */
156     @Override
157     public void onViewCreated(View view, Bundle savedInstanceState) {
158         super.onViewCreated(view, savedInstanceState);
159         ensureGrid();
160     }
161
162     /**
163      * Detach from {@link GridView}
164      */
165     @Override
166     public void onDestroyView() {
167         mHandler.removeCallbacks(mRequestFocus);
168         mGrid = null;
169         mGridShown = false;
170         mEmptyView = mProgressContainer = mGridContainer = null;
171         mStandardEmptyView = null;
172         super.onDestroyView();
173     }
174
175     public static int convertDpToPixels(float dp, Context context){
176         Resources resources = context.getResources();
177         return (int) TypedValue.applyDimension(
178                 TypedValue.COMPLEX_UNIT_DIP,
179                 dp,
180                 resources.getDisplayMetrics()
181         );
182     }
183
184     /**
185      * This method will be called when an item in the grid is selected.
186      * Subclasses should override. Subclasses can call
187      * getGridView().getItemAtPosition(position) if they need to access the
188      * data associated with the selected item.
189      *
190      * @param g The {@link GridView} where the click happened
191      * @param v The view that was clicked within the {@link GridView}
192      * @param position The position of the view in the grid
193      * @param id The row id of the item that was clicked
194      */
195     public void onGridItemClick(GridView g, View v, int position, long id) {
196
197     }
198
199     /**
200      * Provide the cursor for the {@link GridView}.
201      */
202     public void setGridAdapter(ListAdapter adapter) {
203         final boolean hadAdapter = (mAdapter != null);
204         mAdapter = adapter;
205         if (mGrid != null) {
206             mGrid.setAdapter(adapter);
207             if (!mGridShown && !hadAdapter) {
208                 // The grid was hidden, and previously didn't have an
209                 // adapter.  It is now time to show it.
210                 setGridShown(true, (getView().getWindowToken() != null));
211             }
212         }
213     }
214
215     /**
216      * Set the currently selected grid item to the specified
217      * position with the adapter's data
218      *
219      * @param position
220      */
221     public void setSelection(int position) {
222         ensureGrid();
223         mGrid.setSelection(position);
224     }
225
226     /**
227      * Get the position of the currently selected grid item.
228      */
229     public int getSelectedItemPosition() {
230         ensureGrid();
231         return mGrid.getSelectedItemPosition();
232     }
233
234     /**
235      * Get the cursor row ID of the currently selected grid item.
236      */
237     public long getSelectedItemId() {
238         ensureGrid();
239         return mGrid.getSelectedItemId();
240     }
241
242     /**
243      * Get the activity's {@link GridView} widget.
244      */
245     public GridView getGridView() {
246         ensureGrid();
247         return mGrid;
248     }
249
250     /**
251      * The default content for a ListFragment has a TextView that can
252      * be shown when the grid is empty.  If you would like to have it
253      * shown, call this method to supply the text it should use.
254      */
255     public void setEmptyText(CharSequence text) {
256         ensureGrid();
257         if (mStandardEmptyView == null) {
258             throw new IllegalStateException("Can't be used with a custom content view");
259         }
260         mStandardEmptyView.setText(text);
261         if (mEmptyText == null) {
262             mGrid.setEmptyView(mStandardEmptyView);
263         }
264         mEmptyText = text;
265     }
266
267     /**
268      * Control whether the grid is being displayed.  You can make it not
269      * displayed if you are waiting for the initial data to show in it.  During
270      * this time an indeterminant progress indicator will be shown instead.
271      *
272      * <p>Applications do not normally need to use this themselves.  The default
273      * behavior of ListFragment is to start with the grid not being shown, only
274      * showing it once an adapter is given with {@link #setGridAdapter(ListAdapter)}.
275      * If the grid at that point had not been shown, when it does get shown
276      * it will be do without the user ever seeing the hidden state.
277      *
278      * @param shown If true, the grid view is shown; if false, the progress
279      * indicator.  The initial value is true.
280      */
281     public void setGridShown(boolean shown) {
282         setGridShown(shown, true);
283     }
284
285     /**
286      * Like {@link #setGridShown(boolean)}, but no animation is used when
287      * transitioning from the previous state.
288      */
289     public void setGridShownNoAnimation(boolean shown) {
290         setGridShown(shown, false);
291     }
292
293     /**
294      * Control whether the grid is being displayed.  You can make it not
295      * displayed if you are waiting for the initial data to show in it.  During
296      * this time an indeterminant progress indicator will be shown instead.
297      *
298      * @param shown If true, the grid view is shown; if false, the progress
299      * indicator.  The initial value is true.
300      * @param animate If true, an animation will be used to transition to the
301      * new state.
302      */
303     private void setGridShown(boolean shown, boolean animate) {
304         ensureGrid();
305         if (mProgressContainer == null) {
306             throw new IllegalStateException("Can't be used with a custom content view");
307         }
308         if (mGridShown == shown) {
309             return;
310         }
311         mGridShown = shown;
312         if (shown) {
313             if (animate) {
314                 mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
315                         getActivity(), android.R.anim.fade_out));
316                 mGridContainer.startAnimation(AnimationUtils.loadAnimation(
317                         getActivity(), android.R.anim.fade_in));
318             } else {
319                 mProgressContainer.clearAnimation();
320                 mGridContainer.clearAnimation();
321             }
322             mProgressContainer.setVisibility(View.GONE);
323             mGridContainer.setVisibility(View.VISIBLE);
324         } else {
325             if (animate) {
326                 mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
327                         getActivity(), android.R.anim.fade_in));
328                 mGridContainer.startAnimation(AnimationUtils.loadAnimation(
329                         getActivity(), android.R.anim.fade_out));
330             } else {
331                 mProgressContainer.clearAnimation();
332                 mGridContainer.clearAnimation();
333             }
334             mProgressContainer.setVisibility(View.VISIBLE);
335             mGridContainer.setVisibility(View.GONE);
336         }
337     }
338
339     /**
340      * Get the ListAdapter associated with this activity's {@link GridView}.
341      */
342     public ListAdapter getGridAdapter() {
343         return mAdapter;
344     }
345
346     private void ensureGrid() {
347         if (mGrid != null) {
348             return;
349         }
350         View root = getView();
351         if (root == null) {
352             throw new IllegalStateException("Content view not yet created");
353         }
354         if (root instanceof GridView) {
355             mGrid = (GridView) root;
356         } else {
357             mStandardEmptyView = (TextView)root.findViewById(INTERNAL_EMPTY_ID);
358             if (mStandardEmptyView == null) {
359                 mEmptyView = root.findViewById(android.R.id.empty);
360             } else {
361                 mStandardEmptyView.setVisibility(View.GONE);
362             }
363             mProgressContainer = root.findViewById(INTERNAL_PROGRESS_CONTAINER_ID);
364             mGridContainer = root.findViewById(INTERNAL_LIST_CONTAINER_ID);
365             View rawGridView = root.findViewById(android.R.id.list);
366             if (!(rawGridView instanceof GridView)) {
367                 if (rawGridView == null) {
368                     throw new RuntimeException(
369                             "Your content must have a GridView whose id attribute is " +
370                                     "'android.R.id.list'");
371                 }
372                 throw new RuntimeException(
373                         "Content has view with id attribute 'android.R.id.list' "
374                                 + "that is not a GridView class");
375             }
376             mGrid = (GridView) rawGridView;
377             if (mEmptyView != null) {
378                 mGrid.setEmptyView(mEmptyView);
379             } else if (mEmptyText != null) {
380                 mStandardEmptyView.setText(mEmptyText);
381                 mGrid.setEmptyView(mStandardEmptyView);
382             }
383         }
384         mGridShown = true;
385         mGrid.setOnItemClickListener(mOnClickListener);
386         if (mAdapter != null) {
387             ListAdapter adapter = mAdapter;
388             mAdapter = null;
389             setGridAdapter(adapter);
390         } else {
391             // We are starting without an adapter, so assume we won't
392             // have our data right away and start with the progress indicator.
393             if (mProgressContainer != null) {
394                 setGridShown(false, false);
395             }
396         }
397         mHandler.post(mRequestFocus);
398     }
399 }