OSDN Git Service

5ea2342a28b14dd9a17f1cbc9dcb3e29c040ca58
[android-x86/packages-apps-Browser.git] / src / com / android / browser / GearsSettingsDialog.java
1 /*
2  * Copyright (C) 2008 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.browser;
18
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.app.Dialog;
22 import android.content.Context;
23 import android.content.DialogInterface;
24 import android.os.Handler;
25 import android.util.Log;
26 import android.view.LayoutInflater;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.widget.ArrayAdapter;
30 import android.widget.AdapterView;
31 import android.widget.AdapterView.OnItemClickListener;
32 import android.widget.BaseAdapter;
33 import android.widget.Button;
34 import android.widget.CheckBox;
35 import android.widget.CompoundButton;
36 import android.widget.ImageView;
37 import android.widget.ListAdapter;
38 import android.widget.ListView;
39 import android.widget.RadioButton;
40 import android.widget.TextView;
41
42 import com.android.browser.GearsPermissions.OriginPermissions;
43 import com.android.browser.GearsPermissions.Permission;
44 import com.android.browser.GearsPermissions.PermissionsChangesListener;
45 import com.android.browser.GearsPermissions.PermissionType;
46
47 import java.util.Vector;
48 import java.util.List;
49
50 import org.json.JSONArray;
51 import org.json.JSONException;
52 import org.json.JSONObject;
53
54 /**
55  * Gears Settings dialog
56  */
57 class GearsSettingsDialog extends GearsBaseDialog
58     implements PermissionsChangesListener {
59
60   private static final String TAG = "GearsPermissionsDialog";
61   private Vector<OriginPermissions> mSitesPermissions = null;
62   private Vector<OriginPermissions> mOriginalPermissions = null;
63   private Vector<OriginPermissions> mCurrentPermissions = null;
64
65   private Vector<PermissionType> mPermissions;
66   private static final int CONFIRMATION_REMOVE_DIALOG = 1;
67
68   // We declare the permissions globally to simplify the code
69   private final PermissionType LOCAL_STORAGE =
70       new PermissionType(LOCAL_STORAGE_STRING);
71   private final PermissionType LOCATION_DATA =
72       new PermissionType(LOCATION_DATA_STRING);
73
74   private boolean mChanges = false;
75
76   SettingsAdapter mListAdapter;
77
78   public GearsSettingsDialog(Activity activity,
79                              Handler handler,
80                              String arguments) {
81     super (activity, handler, arguments);
82     activity.setContentView(R.layout.gears_settings);
83   }
84
85   public void setup() {
86     // First let's add the permissions' resources
87     LOCAL_STORAGE.setResources(R.string.settings_storage_title,
88                                R.string.settings_storage_subtitle_on,
89                                R.string.settings_storage_subtitle_off);
90     LOCATION_DATA.setResources(R.string.settings_location_title,
91                                R.string.settings_location_subtitle_on,
92                                R.string.settings_location_subtitle_off);
93     // add the permissions to the list of permissions.
94     mPermissions = new Vector<PermissionType>();
95     mPermissions.add(LOCAL_STORAGE);
96     mPermissions.add(LOCATION_DATA);
97     OriginPermissions.setListener(this);
98
99
100     setupDialog();
101
102     // We manage the permissions using three vectors, mSitesPermissions,
103     // mOriginalPermissions and mCurrentPermissions.
104     // The dialog's arguments are parsed and a list of permissions is
105     // generated and stored in those three vectors.
106     // mOriginalPermissions is a separate copy and will not be modified;
107     // mSitesPermissions contains the current permissions _only_ --
108     // if an origin is removed, it is also removed from mSitesPermissions.
109     // Finally, mCurrentPermissions contains the current permissions and
110     // is a clone of mSitesPermissions, but removed sites aren't removed,
111     // their permissions are simply set to PERMISSION_NOT_SET. This
112     // allows us to easily generate the final difference between the
113     // original permissions and the final permissions, while directly
114     // using mSitesPermissions for the listView adapter (SettingsAdapter).
115
116     mSitesPermissions = new Vector<OriginPermissions>();
117     mOriginalPermissions = new Vector<OriginPermissions>();
118
119     try {
120       JSONObject json = new JSONObject(mDialogArguments);
121       if (json.has("permissions")) {
122         JSONArray jsonArray = json.getJSONArray("permissions");
123         for (int i = 0; i < jsonArray.length(); i++) {
124           JSONObject infos = jsonArray.getJSONObject(i);
125           String name = null;
126           int localStorage = PermissionType.PERMISSION_NOT_SET;
127           int locationData = PermissionType.PERMISSION_NOT_SET;
128           if (infos.has("name")) {
129             name = infos.getString("name");
130           }
131           if (infos.has(LOCAL_STORAGE_STRING)) {
132             JSONObject perm = infos.getJSONObject(LOCAL_STORAGE_STRING);
133             if (perm.has("permissionState")) {
134               localStorage = perm.getInt("permissionState");
135             }
136           }
137           if (infos.has(LOCATION_DATA_STRING)) {
138             JSONObject perm = infos.getJSONObject(LOCATION_DATA_STRING);
139             if (perm.has("permissionState")) {
140               locationData = perm.getInt("permissionState");
141             }
142           }
143           OriginPermissions perms = new OriginPermissions(name);
144           perms.setPermission(LOCAL_STORAGE, localStorage);
145           perms.setPermission(LOCATION_DATA, locationData);
146
147           mSitesPermissions.add(perms);
148           mOriginalPermissions.add(new OriginPermissions(perms));
149         }
150       }
151     } catch (JSONException e) {
152       Log.e(TAG, "JSON exception ", e);
153     }
154     mCurrentPermissions = (Vector<OriginPermissions>)mSitesPermissions.clone();
155
156     View listView = findViewById(R.id.sites_list);
157     if (listView != null) {
158       ListView list = (ListView) listView;
159       mListAdapter = new SettingsAdapter(mActivity, mSitesPermissions);
160       list.setAdapter(mListAdapter);
161       list.setScrollBarStyle(android.view.View.SCROLLBARS_OUTSIDE_INSET);
162       list.setOnItemClickListener(mListAdapter);
163     }
164     if (mDebug) {
165       printPermissions();
166     }
167   }
168
169   private void setMainTitle() {
170     String windowTitle = mActivity.getString(R.string.pref_extras_gears_settings);
171     mActivity.setTitle(windowTitle);
172   }
173
174   public void setupDialog() {
175     setMainTitle();
176   }
177
178   /**
179    * GearsPermissions.PermissionsChangesListener delegate
180    */
181   public boolean setPermission(PermissionType type, int perm) {
182     if (mChanges == false) {
183       mChanges = true;
184     }
185     return mChanges;
186   }
187
188   public boolean handleBackButton() {
189     return mListAdapter.backButtonPressed();
190   }
191
192   /**
193    * We use this to create a confirmation dialog when the user
194    * clicks on "remove this site from gears"
195    */
196   public Dialog onCreateDialog(int id) {
197     return new AlertDialog.Builder(mActivity)
198         .setTitle(R.string.settings_confirmation_remove_title)
199         .setMessage(R.string.settings_confirmation_remove)
200         .setPositiveButton(android.R.string.ok,
201                            new AlertDialog.OnClickListener() {
202           public void onClick(DialogInterface dlg, int which) {
203             mListAdapter.removeCurrentSite();
204           }
205         })
206         .setNegativeButton(android.R.string.cancel, null)
207         .setIcon(android.R.drawable.ic_dialog_alert)
208         .create();
209   }
210
211   /**
212    * Adapter class for the list view in the settings dialog
213    *
214    * We first display a list of all the origins (sites), or
215    * a message saying that no permission is set if the list is empty.
216    * When the user click on one of the origin, we then display
217    * the list of the permissions existing for that origin.
218    * Each permission can be either allowed or denied by clicking
219    * on the checkbox.
220    * The last row is a special case, allowing to remove the entire origin.
221    */
222   class SettingsAdapter extends BaseAdapter
223       implements AdapterView.OnItemClickListener {
224     private Activity mContext;
225     private List mItems;
226     private OriginPermissions mCurrentSite;
227     private Vector mCurrentPermissions;
228     private int MAX_ROW_HEIGHT = 64;
229
230     SettingsAdapter(Activity context, List items) {
231       mContext = context;
232       mItems = items;
233       mCurrentSite = null;
234     }
235
236     public int getCount() {
237       if (mCurrentSite == null) {
238         int size = mItems.size();
239         if (size == 0) {
240           return 1;
241         } else {
242           return size;
243         }
244       }
245       return mCurrentPermissions.size() + 1;
246     }
247
248     public long getItemId(int position) {
249       return position;
250     }
251
252     private String shortName(String url) {
253         // We remove the http and https prefix
254         if (url.startsWith("http://")) {
255           return url.substring(7);
256         }
257         if (url.startsWith("https://")) {
258           return url.substring(8);
259         }
260         return url;
261     }
262
263     public Object getItem(int position) {
264       if (mCurrentSite == null) {
265         if (mItems.size() == 0) {
266           return null;
267         } else {
268           return mItems.get(position);
269         }
270       }
271       return mCurrentPermissions.get(position);
272     }
273
274     public View getView(int position, View convertView, ViewGroup parent) {
275       View row = convertView;
276       if (row == null) { // no cached view, we create one
277         LayoutInflater inflater = (LayoutInflater) getSystemService(
278             Context.LAYOUT_INFLATER_SERVICE);
279         row = inflater.inflate(R.layout.gears_settings_row, null);
280       }
281       row.setMinimumHeight(MAX_ROW_HEIGHT);
282
283       if (mCurrentSite == null) {
284         if (mItems.size() == 0) {
285           hideView(row, R.id.title);
286           hideView(row, R.id.subtitle);
287           hideView(row, R.id.checkbox);
288           hideView(row, R.id.icon);
289           setText(row, R.id.info, R.string.settings_empty);
290         } else {
291           hideView(row, R.id.subtitle);
292           hideView(row, R.id.info);
293           hideView(row, R.id.checkbox);
294           OriginPermissions perms = (OriginPermissions) mItems.get(position);
295           setText(row, R.id.title, shortName(perms.getOrigin()));
296           showView(row, R.id.icon);
297         }
298       } else {
299         if (position == getCount() - 1) {
300           // last position: "remove this site from gears"
301           hideView(row, R.id.subtitle);
302           hideView(row, R.id.info);
303           hideView(row, R.id.checkbox);
304           hideView(row, R.id.icon);
305           setText(row, R.id.title, R.string.settings_remove_site);
306         } else {
307           hideView(row, R.id.info);
308           hideView(row, R.id.icon);
309           showView(row, R.id.checkbox);
310
311           PermissionType type =
312               (PermissionType) mCurrentPermissions.get(position);
313           setText(row, R.id.title, type.getTitleRsc());
314
315           View checkboxView = row.findViewById(R.id.checkbox);
316           if (checkboxView != null) {
317             CheckBox checkbox = (CheckBox) checkboxView;
318             int perm = mCurrentSite.getPermission(type);
319             if (perm == PermissionType.PERMISSION_DENIED) {
320               setText(row, R.id.subtitle, type.getSubtitleOffRsc());
321               checkbox.setChecked(false);
322             } else {
323               setText(row, R.id.subtitle, type.getSubtitleOnRsc());
324               checkbox.setChecked(true);
325             }
326           }
327         }
328       }
329       return row;
330     }
331
332     public void removeCurrentSite() {
333       mCurrentSite.setPermission(LOCAL_STORAGE,
334                                  PermissionType.PERMISSION_NOT_SET);
335       mCurrentSite.setPermission(LOCATION_DATA,
336                                  PermissionType.PERMISSION_NOT_SET);
337       mSitesPermissions.remove(mCurrentSite);
338       mCurrentSite = null;
339       setMainTitle();
340       notifyDataSetChanged();
341     }
342
343     public void onItemClick(AdapterView<?> parent,
344                             View view,
345                             int position,
346                             long id) {
347       if (mItems.size() == 0) {
348         return;
349       }
350       if (mCurrentSite == null) {
351          mCurrentSite = (OriginPermissions) mItems.get(position);
352          mCurrentPermissions = new Vector();
353          for (int i = 0; i < mPermissions.size(); i++) {
354            PermissionType type = mPermissions.get(i);
355            int perm = mCurrentSite.getPermission(type);
356            if (perm != PermissionType.PERMISSION_NOT_SET) {
357              mCurrentPermissions.add(type);
358            }
359          }
360          mContext.setTitle(shortName(mCurrentSite.getOrigin()));
361       } else {
362         if (position == getCount() - 1) { // last item (remove site)
363           // Ask the user to confirm
364           // If yes, removeCurrentSite() will be called via the dialog callback.
365           mActivity.showDialog(CONFIRMATION_REMOVE_DIALOG);
366         } else {
367           PermissionType type =
368               (PermissionType) mCurrentPermissions.get(position);
369           if (mCurrentSite.getPermission(type) ==
370               PermissionType.PERMISSION_ALLOWED) {
371             mCurrentSite.setPermission(type, PermissionType.PERMISSION_DENIED);
372           } else {
373             mCurrentSite.setPermission(type, PermissionType.PERMISSION_ALLOWED);
374           }
375         }
376       }
377       notifyDataSetChanged();
378     }
379
380     public boolean backButtonPressed() {
381       if (mCurrentSite != null) { // we intercept the back button
382         mCurrentSite = null;
383         setMainTitle();
384         notifyDataSetChanged();
385         return true;
386       }
387       return false;
388     }
389
390   }
391
392   /**
393    * Utility method used in debug mode to print the list of
394    * permissions (original values and current values).
395    */
396   public void printPermissions() {
397     Log.v(TAG, "Original Permissions: ");
398     for (int i = 0; i < mOriginalPermissions.size(); i++) {
399       OriginPermissions p = mOriginalPermissions.get(i);
400       p.print();
401     }
402     Log.v(TAG, "Current Permissions: ");
403     for (int i = 0; i < mSitesPermissions.size(); i++) {
404       OriginPermissions p = mSitesPermissions.get(i);
405       p.print();
406     }
407   }
408
409   /**
410    * Computes the difference between the original permissions and the
411    * current ones. Returns a json-formatted string.
412    * It is used by the Settings dialog.
413    */
414   public String computeDiff(boolean modif) {
415     String ret = null;
416     try {
417       JSONObject results = new JSONObject();
418       JSONArray permissions = new JSONArray();
419
420       for (int i = 0; modif && i < mOriginalPermissions.size(); i++) {
421         OriginPermissions original = mOriginalPermissions.get(i);
422         OriginPermissions current = mCurrentPermissions.get(i);
423         JSONObject permission = new JSONObject();
424         boolean modifications = false;
425
426         for (int j = 0; j < mPermissions.size(); j++) {
427           PermissionType type = mPermissions.get(j);
428
429           if (current.getPermission(type) != original.getPermission(type)) {
430             JSONObject state = new JSONObject();
431             state.put("permissionState", current.getPermission(type));
432             permission.put(type.getName(), state);
433             modifications = true;
434           }
435         }
436
437         if (modifications) {
438           permission.put("name", current.getOrigin());
439           permissions.put(permission);
440         }
441       }
442       results.put("modifiedOrigins", permissions);
443       ret = results.toString();
444     } catch (JSONException e) {
445       Log.e(TAG, "JSON exception ", e);
446     }
447     return ret;
448   }
449
450   public String closeDialog(int closingType) {
451     String ret = computeDiff(mChanges);
452
453     if (mDebug) {
454       printPermissions();
455     }
456
457     return ret;
458   }
459
460 }