blob: 56a1d8d95462a710eb313fb237423e9a47d7a43d [file] [log] [blame]
The Android Open Source Projected217d92008-12-17 18:05:52 -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.content.Context;
21import android.os.Handler;
22import android.util.Log;
23import android.view.LayoutInflater;
24import android.view.View;
25import android.view.ViewGroup;
26import android.widget.ArrayAdapter;
27import android.widget.Button;
28import android.widget.CompoundButton;
29import android.widget.ImageView;
30import android.widget.ListAdapter;
31import android.widget.ListView;
32import android.widget.RadioButton;
33import android.widget.TextView;
34
35import com.android.browser.GearsPermissions.OriginPermissions;
36import com.android.browser.GearsPermissions.PermissionsChangesListener;
37import com.android.browser.GearsPermissions.PermissionType;
38
39import java.util.Vector;
40import java.util.List;
41
42import org.json.JSONArray;
43import org.json.JSONException;
44import org.json.JSONObject;
45
46/**
47 * Gears Settings dialog
48 */
49class GearsSettingsDialog extends GearsBaseDialog
50 implements PermissionsChangesListener {
51
52 private static final String TAG = "GearsPermissionsDialog";
53 private Vector<OriginPermissions> mSitesPermissions = null;
54 private Vector<OriginPermissions> mOriginalPermissions = null;
55 private Vector<OriginPermissions> mCurrentPermissions = null;
56
57 private Vector<PermissionType> mPermissions;
58
59 // We declare the permissions globally to simplify the code
60 private final PermissionType LOCAL_STORAGE =
61 new PermissionType(LOCAL_STORAGE_STRING);
62 private final PermissionType LOCATION_DATA =
63 new PermissionType(LOCATION_DATA_STRING);
64
65 private boolean mChanges = false;
66
67
68 public GearsSettingsDialog(Activity activity,
69 Handler handler,
70 String arguments) {
71 super (activity, handler, arguments);
72 }
73
74 public void setup() {
75 // First let's add the permissions' resources
76 LOCAL_STORAGE.setResources(R.id.local_storage_choice,
77 R.id.local_storage_allowed,
78 R.id.local_storage_denied);
79
80 LOCATION_DATA.setResources(R.id.location_data_choice,
81 R.id.location_data_allowed,
82 R.id.location_data_denied);
83
84 // add the permissions to the list of permissions.
85 mPermissions = new Vector<PermissionType>();
86 mPermissions.add(LOCAL_STORAGE);
87 mPermissions.add(LOCATION_DATA);
88 OriginPermissions.setListener(this);
89
90
91 inflate(R.layout.gears_dialog_settings, R.id.panel_content);
92 setupDialog();
93 setupButtons(0,
94 R.string.settings_button_allow,
95 R.string.settings_button_deny);
96
97 // by default disable the allow button (it will get enabled if
98 // something is changed by the user)
99 View buttonView = findViewById(R.id.button_allow);
100 if (buttonView != null) {
101 Button button = (Button) buttonView;
102 button.setEnabled(false);
103 }
104
105 View gearsVersionView = findViewById(R.id.gears_version);
106 if (gearsVersionView != null) {
107 TextView gearsVersion = (TextView) gearsVersionView;
108 gearsVersion.setText(mGearsVersion);
109 }
110
111 // We manage the permissions using three vectors, mSitesPermissions,
112 // mOriginalPermissions and mCurrentPermissions.
113 // The dialog's arguments are parsed and a list of permissions is
114 // generated and stored in those three vectors.
115 // mOriginalPermissions is a separate copy and will not be modified;
116 // mSitesPermissions contains the current permissions _only_ --
117 // if an origin is removed, it is also removed from mSitesPermissions.
118 // Finally, mCurrentPermissions contains the current permissions and
119 // is a clone of mSitesPermissions, but removed sites aren't removed,
120 // their permissions are simply set to PERMISSION_NOT_SET. This
121 // allows us to easily generate the final difference between the
122 // original permissions and the final permissions, while directly
123 // using mSitesPermissions for the listView adapter (SettingsAdapter).
124
125 mSitesPermissions = new Vector<OriginPermissions>();
126 mOriginalPermissions = new Vector<OriginPermissions>();
127
128 try {
129 JSONObject json = new JSONObject(mDialogArguments);
130 if (json.has("permissions")) {
131 JSONArray jsonArray = json.getJSONArray("permissions");
132 for (int i = 0; i < jsonArray.length(); i++) {
133 JSONObject infos = jsonArray.getJSONObject(i);
134 String name = null;
135 int localStorage = PermissionType.PERMISSION_NOT_SET;
136 int locationData = PermissionType.PERMISSION_NOT_SET;
137 if (infos.has("name")) {
138 name = infos.getString("name");
139 }
140 if (infos.has(LOCAL_STORAGE_STRING)) {
141 JSONObject perm = infos.getJSONObject(LOCAL_STORAGE_STRING);
142 if (perm.has("permissionState")) {
143 localStorage = perm.getInt("permissionState");
144 }
145 }
146 if (infos.has(LOCATION_DATA_STRING)) {
147 JSONObject perm = infos.getJSONObject(LOCATION_DATA_STRING);
148 if (perm.has("permissionState")) {
149 locationData = perm.getInt("permissionState");
150 }
151 }
152 OriginPermissions perms = new OriginPermissions(name);
153 perms.setPermission(LOCAL_STORAGE, localStorage);
154 perms.setPermission(LOCATION_DATA, locationData);
155
156 mSitesPermissions.add(perms);
157 mOriginalPermissions.add(new OriginPermissions(perms));
158 }
159 }
160 } catch (JSONException e) {
161 Log.e(TAG, "JSON exception ", e);
162 }
163 mCurrentPermissions = (Vector<OriginPermissions>)mSitesPermissions.clone();
164
165 View listView = findViewById(R.id.sites_list);
166 if (listView != null) {
167 ListView list = (ListView) listView;
168 list.setAdapter(new SettingsAdapter(mActivity, mSitesPermissions));
The Android Open Source Project765e7c92009-01-09 17:51:25 -0800169 list.setScrollBarStyle(android.view.View.SCROLLBARS_OUTSIDE_INSET);
The Android Open Source Projected217d92008-12-17 18:05:52 -0800170 }
171 if (mDebug) {
172 printPermissions();
173 }
174 }
175
176 public void setupDialog() {
177 View dialogTitleView = findViewById(R.id.dialog_title);
178 if (dialogTitleView != null) {
179 TextView dialogTitle = (TextView) dialogTitleView;
180 dialogTitle.setText(R.string.settings_title);
181 dialogTitle.setVisibility(View.VISIBLE);
182 }
183 View dialogSubtitleView = findViewById(R.id.dialog_subtitle);
184 if (dialogSubtitleView != null) {
185 TextView dialogSubtitle = (TextView) dialogSubtitleView;
186 dialogSubtitle.setText(R.string.settings_message);
187 dialogSubtitle.setVisibility(View.VISIBLE);
188 }
189 View iconView = findViewById(R.id.icon);
190 if (iconView != null) {
191 ImageView icon = (ImageView) iconView;
192 icon.setImageResource(R.drawable.gears_icon_32x32);
193 }
194 }
195
196 /**
197 * GearsPermissions.PermissionsChangesListener delegate
198 */
199 public boolean setPermission(PermissionType type, int perm) {
200 if (mChanges == false) {
201 signalChanges();
202 }
203 return mChanges;
204 }
205
206 /**
207 * Controller class for binding the model (OriginPermissions) with
208 * the UI.
209 */
210 class PermissionController {
211 final static int ALLOWED_BUTTON = 1;
212 final static int DENIED_BUTTON = 2;
213 private int mButtonType;
214 private PermissionType mPermissionType;
215 private OriginPermissions mPermissions;
216
217 PermissionController(PermissionType permissionType, int buttonType,
218 OriginPermissions permissions) {
219 mPermissionType = permissionType;
220 mButtonType = buttonType;
221 mPermissions = permissions;
222 }
223
224 public boolean isChecked() {
225 boolean checked = false;
226
227 switch (mButtonType) {
228 case ALLOWED_BUTTON:
229 if (mPermissions.getPermission(mPermissionType) ==
230 PermissionType.PERMISSION_ALLOWED) {
231 checked = true;
232 } break;
233 case DENIED_BUTTON:
234 if (mPermissions.getPermission(mPermissionType) ==
235 PermissionType.PERMISSION_DENIED) {
236 checked = true;
237 }
238 }
239 return checked;
240 }
241
242 public String print() {
243 return printType() + " for " + mPermissions.getOrigin();
244 }
245
246 private String printType() {
247 switch (mButtonType) {
248 case ALLOWED_BUTTON:
249 return "ALLOWED_BUTTON";
250 case DENIED_BUTTON:
251 return "DENIED_BUTTON";
252 }
253 return "UNKNOWN BUTTON";
254 }
255
256 public void changed(boolean isChecked) {
257 if (isChecked == isChecked()) {
258 return; // already set
259 }
260
261 switch (mButtonType) {
262 case ALLOWED_BUTTON:
263 mPermissions.setPermission(mPermissionType,
264 PermissionType.PERMISSION_ALLOWED);
265 break;
266 case DENIED_BUTTON:
267 mPermissions.setPermission(mPermissionType,
268 PermissionType.PERMISSION_DENIED);
269 break;
270 }
271 }
272 }
273
274
275
276 /**
277 * Adapter class for the list view in the settings dialog
278 *
279 * Every row in the settings dialog display the permissions
280 * for a given origin. For every type of permission
281 * (location, local data...) there is two radio buttons to
282 * authorize or deny the permission.
283 * A remove button is also present to let the user remove
284 * all the authorization of an origin in one step.
285 */
286 class SettingsAdapter extends ArrayAdapter {
287 private Activity mContext;
288 private List mItems;
289
290 SettingsAdapter(Activity context, List items) {
291 super(context, R.layout.gears_dialog_settings_row, items);
292 mContext = context;
293 mItems = items;
294 }
295
296 /*
297 * setup the necessary listeners for the radiobuttons
298 * When the buttons are clicked the permissions change.
299 */
300 private void createAndSetButtonListener(View buttonView,
301 OriginPermissions perms, PermissionType permissionType,
302 int buttonType) {
303 if (buttonView == null) {
304 return;
305 }
306 RadioButton button = (RadioButton) buttonView;
307
308 button.setOnCheckedChangeListener(null);
309 PermissionController p = new PermissionController(permissionType,
310 buttonType, perms);
311 button.setTag(p);
312
313 CompoundButton.OnCheckedChangeListener listener =
314 new CompoundButton.OnCheckedChangeListener() {
315 public void onCheckedChanged(CompoundButton buttonView,
316 boolean isChecked) {
317 PermissionController perm = (PermissionController)buttonView.getTag();
318 perm.changed(isChecked);
319 }
320 };
321
322 button.setOnCheckedChangeListener(listener);
323
324 if (p.isChecked() != button.isChecked()) {
325 button.setChecked(p.isChecked());
326 }
327 }
328
329 /*
330 * setup the remove button for an origin: each row has a global
331 * remove button in addition to the radio buttons controlling the
332 * permissions.
333 */
334 private void setRemoveButton(Button button, OriginPermissions perms) {
335 Button.OnClickListener listener = new Button.OnClickListener() {
336 public void onClick(View buttonView) {
337 if (mChanges == false) {
338 signalChanges();
339 }
340 OriginPermissions perm = (OriginPermissions) buttonView.getTag();
341 perm.setPermission(LOCAL_STORAGE, PermissionType.PERMISSION_NOT_SET);
342 perm.setPermission(LOCATION_DATA, PermissionType.PERMISSION_NOT_SET);
343 mSitesPermissions.remove(perm);
344
345 View view = findViewById(R.id.sites_list);
346 if (view != null) {
347 ListView listView = (ListView) view;
348 ListAdapter listAdapter = listView.getAdapter();
349 if (listAdapter != null) {
350 SettingsAdapter settingsAdapter = (SettingsAdapter) listAdapter;
351 settingsAdapter.notifyDataSetChanged();
352 }
353 }
354 }
355 };
356 button.setTag(perms);
357 button.setOnClickListener(listener);
The Android Open Source Project765e7c92009-01-09 17:51:25 -0800358 displayAsLink(button);
The Android Open Source Projected217d92008-12-17 18:05:52 -0800359 }
360
361 public View getView(int position, View convertView, ViewGroup parent) {
362 View row = convertView;
363 if (row == null) { // no cached view, we create one
364 LayoutInflater inflater = (LayoutInflater) getSystemService(
365 Context.LAYOUT_INFLATER_SERVICE);
366 row = inflater.inflate(R.layout.gears_dialog_settings_row, null);
367 }
368
369 OriginPermissions perms = (OriginPermissions) mItems.get(position);
370
371 View nameView = row.findViewById(R.id.origin_name);
372 if (nameView != null) {
373 TextView originName = (TextView) nameView;
374 originName.setText(perms.getOrigin());
375 }
376
377 View removeButtonView = row.findViewById(R.id.origin_remove);
378 if (removeButtonView != null) {
379 Button removeButton = (Button) removeButtonView;
380 setRemoveButton(removeButton, perms);
381 }
382
383 for (int i = 0; i < mPermissions.size(); i++) {
384 PermissionType type = mPermissions.get(i);
385 int rowRsc = type.getRowRsc();
386 int allowedButtonRsc = type.getAllowedButtonRsc();
387 int deniedButtonRsc = type.getDeniedButtonRsc();
388
389 View rowView = row.findViewById(rowRsc);
390 if (rowView != null) {
391 int perm = perms.getPermission(type);
392 if (perm != PermissionType.PERMISSION_NOT_SET) {
393 createAndSetButtonListener(row.findViewById(allowedButtonRsc),
394 perms, type, PermissionController.ALLOWED_BUTTON);
395 createAndSetButtonListener(row.findViewById(deniedButtonRsc),
396 perms, type, PermissionController.DENIED_BUTTON);
397 rowView.setVisibility(View.VISIBLE);
398 } else {
399 rowView.setVisibility(View.GONE);
400 }
401 }
402 }
403
404 return row;
405 }
406 }
407
408 /**
409 * Utility method used in debug mode to print the list of
410 * permissions (original values and current values).
411 */
412 public void printPermissions() {
413 Log.v(TAG, "Original Permissions: ");
414 for (int i = 0; i < mOriginalPermissions.size(); i++) {
415 OriginPermissions p = mOriginalPermissions.get(i);
416 p.print();
417 }
418 Log.v(TAG, "Current Permissions: ");
419 for (int i = 0; i < mSitesPermissions.size(); i++) {
420 OriginPermissions p = mSitesPermissions.get(i);
421 p.print();
422 }
423 }
424
425 /**
426 * Utility method used by the settings dialog, signaling
427 * the user the settings have been modified.
428 * We reflect this by enabling the Allow button (disabled
429 * by default).
430 */
431 public void signalChanges() {
432 View view = findViewById(R.id.button_allow);
433 if (view != null) {
434 Button button = (Button) view;
435 button.setEnabled(true);
436 }
437 mChanges = true;
438 }
439
440 /**
441 * Computes the difference between the original permissions and the
442 * current ones. Returns a json-formatted string.
443 * It is used by the Settings dialog.
444 */
445 public String computeDiff(boolean modif) {
446 String ret = null;
447 try {
448 JSONObject results = new JSONObject();
449 JSONArray permissions = new JSONArray();
450
451 for (int i = 0; modif && i < mOriginalPermissions.size(); i++) {
452 OriginPermissions original = mOriginalPermissions.get(i);
453 OriginPermissions current = mCurrentPermissions.get(i);
454 JSONObject permission = new JSONObject();
455 boolean modifications = false;
456
457 for (int j = 0; j < mPermissions.size(); j++) {
458 PermissionType type = mPermissions.get(j);
459
460 if (current.getPermission(type) != original.getPermission(type)) {
461 JSONObject state = new JSONObject();
462 state.put("permissionState", current.getPermission(type));
463 permission.put(type.getName(), state);
464 modifications = true;
465 }
466 }
467
468 if (modifications) {
469 permission.put("name", current.getOrigin());
470 permissions.put(permission);
471 }
472 }
473 results.put("modifiedOrigins", permissions);
474 ret = results.toString();
475 } catch (JSONException e) {
476 Log.e(TAG, "JSON exception ", e);
477 }
478 return ret;
479 }
480
481 public String closeDialog(int closingType) {
482 String ret = null;
483 switch (closingType) {
484 case ALWAYS_DENY:
485 ret = "{\"allow\": false }";
486 break;
487 case ALLOW:
488 ret = computeDiff(true);
489 break;
490 case DENY:
491 ret = computeDiff(false);
492 break;
493 }
494
495 if (mDebug) {
496 printPermissions();
497 }
498
499 return ret;
500 }
501
502}