blob: 5ea2342a28b14dd9a17f1cbc9dcb3e29c040ca58 [file] [log] [blame]
The Android Open Source Project0c908882009-03-03 19:32:16 -08001/*
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
17package com.android.browser;
18
19import android.app.Activity;
20import android.app.AlertDialog;
21import android.app.Dialog;
22import android.content.Context;
23import android.content.DialogInterface;
24import android.os.Handler;
25import android.util.Log;
26import android.view.LayoutInflater;
27import android.view.View;
28import android.view.ViewGroup;
29import android.widget.ArrayAdapter;
30import android.widget.AdapterView;
31import android.widget.AdapterView.OnItemClickListener;
32import android.widget.BaseAdapter;
33import android.widget.Button;
34import android.widget.CheckBox;
35import android.widget.CompoundButton;
36import android.widget.ImageView;
37import android.widget.ListAdapter;
38import android.widget.ListView;
39import android.widget.RadioButton;
40import android.widget.TextView;
41
42import com.android.browser.GearsPermissions.OriginPermissions;
43import com.android.browser.GearsPermissions.Permission;
44import com.android.browser.GearsPermissions.PermissionsChangesListener;
45import com.android.browser.GearsPermissions.PermissionType;
46
47import java.util.Vector;
48import java.util.List;
49
50import org.json.JSONArray;
51import org.json.JSONException;
52import org.json.JSONObject;
53
54/**
55 * Gears Settings dialog
56 */
57class 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}