blob: dead4f247c2c98f9633901a993a4b149bbb8b8e8 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.browser;
import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TextView;
import com.android.browser.GearsPermissions.OriginPermissions;
import com.android.browser.GearsPermissions.PermissionsChangesListener;
import com.android.browser.GearsPermissions.PermissionType;
import java.util.Vector;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Gears Settings dialog
*/
class GearsSettingsDialog extends GearsBaseDialog
implements PermissionsChangesListener {
private static final String TAG = "GearsPermissionsDialog";
private Vector<OriginPermissions> mSitesPermissions = null;
private Vector<OriginPermissions> mOriginalPermissions = null;
private Vector<OriginPermissions> mCurrentPermissions = null;
private Vector<PermissionType> mPermissions;
// We declare the permissions globally to simplify the code
private final PermissionType LOCAL_STORAGE =
new PermissionType(LOCAL_STORAGE_STRING);
private final PermissionType LOCATION_DATA =
new PermissionType(LOCATION_DATA_STRING);
private boolean mChanges = false;
public GearsSettingsDialog(Activity activity,
Handler handler,
String arguments) {
super (activity, handler, arguments);
}
public void setup() {
// First let's add the permissions' resources
LOCAL_STORAGE.setResources(R.id.local_storage_choice,
R.id.local_storage_allowed,
R.id.local_storage_denied);
LOCATION_DATA.setResources(R.id.location_data_choice,
R.id.location_data_allowed,
R.id.location_data_denied);
// add the permissions to the list of permissions.
mPermissions = new Vector<PermissionType>();
mPermissions.add(LOCAL_STORAGE);
mPermissions.add(LOCATION_DATA);
OriginPermissions.setListener(this);
inflate(R.layout.gears_dialog_settings, R.id.panel_content);
setupDialog();
setupButtons(0,
R.string.settings_button_allow,
R.string.settings_button_deny);
// by default disable the allow button (it will get enabled if
// something is changed by the user)
View buttonView = findViewById(R.id.button_allow);
if (buttonView != null) {
Button button = (Button) buttonView;
button.setEnabled(false);
}
View gearsVersionView = findViewById(R.id.gears_version);
if (gearsVersionView != null) {
TextView gearsVersion = (TextView) gearsVersionView;
gearsVersion.setText(mGearsVersion);
}
// We manage the permissions using three vectors, mSitesPermissions,
// mOriginalPermissions and mCurrentPermissions.
// The dialog's arguments are parsed and a list of permissions is
// generated and stored in those three vectors.
// mOriginalPermissions is a separate copy and will not be modified;
// mSitesPermissions contains the current permissions _only_ --
// if an origin is removed, it is also removed from mSitesPermissions.
// Finally, mCurrentPermissions contains the current permissions and
// is a clone of mSitesPermissions, but removed sites aren't removed,
// their permissions are simply set to PERMISSION_NOT_SET. This
// allows us to easily generate the final difference between the
// original permissions and the final permissions, while directly
// using mSitesPermissions for the listView adapter (SettingsAdapter).
mSitesPermissions = new Vector<OriginPermissions>();
mOriginalPermissions = new Vector<OriginPermissions>();
try {
JSONObject json = new JSONObject(mDialogArguments);
if (json.has("permissions")) {
JSONArray jsonArray = json.getJSONArray("permissions");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject infos = jsonArray.getJSONObject(i);
String name = null;
int localStorage = PermissionType.PERMISSION_NOT_SET;
int locationData = PermissionType.PERMISSION_NOT_SET;
if (infos.has("name")) {
name = infos.getString("name");
}
if (infos.has(LOCAL_STORAGE_STRING)) {
JSONObject perm = infos.getJSONObject(LOCAL_STORAGE_STRING);
if (perm.has("permissionState")) {
localStorage = perm.getInt("permissionState");
}
}
if (infos.has(LOCATION_DATA_STRING)) {
JSONObject perm = infos.getJSONObject(LOCATION_DATA_STRING);
if (perm.has("permissionState")) {
locationData = perm.getInt("permissionState");
}
}
OriginPermissions perms = new OriginPermissions(name);
perms.setPermission(LOCAL_STORAGE, localStorage);
perms.setPermission(LOCATION_DATA, locationData);
mSitesPermissions.add(perms);
mOriginalPermissions.add(new OriginPermissions(perms));
}
}
} catch (JSONException e) {
Log.e(TAG, "JSON exception ", e);
}
mCurrentPermissions = (Vector<OriginPermissions>)mSitesPermissions.clone();
View listView = findViewById(R.id.sites_list);
if (listView != null) {
ListView list = (ListView) listView;
list.setAdapter(new SettingsAdapter(mActivity, mSitesPermissions));
}
if (mDebug) {
printPermissions();
}
}
public void setupDialog() {
View dialogTitleView = findViewById(R.id.dialog_title);
if (dialogTitleView != null) {
TextView dialogTitle = (TextView) dialogTitleView;
dialogTitle.setText(R.string.settings_title);
dialogTitle.setVisibility(View.VISIBLE);
}
View dialogSubtitleView = findViewById(R.id.dialog_subtitle);
if (dialogSubtitleView != null) {
TextView dialogSubtitle = (TextView) dialogSubtitleView;
dialogSubtitle.setText(R.string.settings_message);
dialogSubtitle.setVisibility(View.VISIBLE);
}
View iconView = findViewById(R.id.icon);
if (iconView != null) {
ImageView icon = (ImageView) iconView;
icon.setImageResource(R.drawable.gears_icon_32x32);
}
}
/**
* GearsPermissions.PermissionsChangesListener delegate
*/
public boolean setPermission(PermissionType type, int perm) {
if (mChanges == false) {
signalChanges();
}
return mChanges;
}
/**
* Controller class for binding the model (OriginPermissions) with
* the UI.
*/
class PermissionController {
final static int ALLOWED_BUTTON = 1;
final static int DENIED_BUTTON = 2;
private int mButtonType;
private PermissionType mPermissionType;
private OriginPermissions mPermissions;
PermissionController(PermissionType permissionType, int buttonType,
OriginPermissions permissions) {
mPermissionType = permissionType;
mButtonType = buttonType;
mPermissions = permissions;
}
public boolean isChecked() {
boolean checked = false;
switch (mButtonType) {
case ALLOWED_BUTTON:
if (mPermissions.getPermission(mPermissionType) ==
PermissionType.PERMISSION_ALLOWED) {
checked = true;
} break;
case DENIED_BUTTON:
if (mPermissions.getPermission(mPermissionType) ==
PermissionType.PERMISSION_DENIED) {
checked = true;
}
}
return checked;
}
public String print() {
return printType() + " for " + mPermissions.getOrigin();
}
private String printType() {
switch (mButtonType) {
case ALLOWED_BUTTON:
return "ALLOWED_BUTTON";
case DENIED_BUTTON:
return "DENIED_BUTTON";
}
return "UNKNOWN BUTTON";
}
public void changed(boolean isChecked) {
if (isChecked == isChecked()) {
return; // already set
}
switch (mButtonType) {
case ALLOWED_BUTTON:
mPermissions.setPermission(mPermissionType,
PermissionType.PERMISSION_ALLOWED);
break;
case DENIED_BUTTON:
mPermissions.setPermission(mPermissionType,
PermissionType.PERMISSION_DENIED);
break;
}
}
}
/**
* Adapter class for the list view in the settings dialog
*
* Every row in the settings dialog display the permissions
* for a given origin. For every type of permission
* (location, local data...) there is two radio buttons to
* authorize or deny the permission.
* A remove button is also present to let the user remove
* all the authorization of an origin in one step.
*/
class SettingsAdapter extends ArrayAdapter {
private Activity mContext;
private List mItems;
SettingsAdapter(Activity context, List items) {
super(context, R.layout.gears_dialog_settings_row, items);
mContext = context;
mItems = items;
}
/*
* setup the necessary listeners for the radiobuttons
* When the buttons are clicked the permissions change.
*/
private void createAndSetButtonListener(View buttonView,
OriginPermissions perms, PermissionType permissionType,
int buttonType) {
if (buttonView == null) {
return;
}
RadioButton button = (RadioButton) buttonView;
button.setOnCheckedChangeListener(null);
PermissionController p = new PermissionController(permissionType,
buttonType, perms);
button.setTag(p);
CompoundButton.OnCheckedChangeListener listener =
new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
PermissionController perm = (PermissionController)buttonView.getTag();
perm.changed(isChecked);
}
};
button.setOnCheckedChangeListener(listener);
if (p.isChecked() != button.isChecked()) {
button.setChecked(p.isChecked());
}
}
/*
* setup the remove button for an origin: each row has a global
* remove button in addition to the radio buttons controlling the
* permissions.
*/
private void setRemoveButton(Button button, OriginPermissions perms) {
Button.OnClickListener listener = new Button.OnClickListener() {
public void onClick(View buttonView) {
if (mChanges == false) {
signalChanges();
}
OriginPermissions perm = (OriginPermissions) buttonView.getTag();
perm.setPermission(LOCAL_STORAGE, PermissionType.PERMISSION_NOT_SET);
perm.setPermission(LOCATION_DATA, PermissionType.PERMISSION_NOT_SET);
mSitesPermissions.remove(perm);
View view = findViewById(R.id.sites_list);
if (view != null) {
ListView listView = (ListView) view;
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter != null) {
SettingsAdapter settingsAdapter = (SettingsAdapter) listAdapter;
settingsAdapter.notifyDataSetChanged();
}
}
}
};
button.setTag(perms);
button.setOnClickListener(listener);
}
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) { // no cached view, we create one
LayoutInflater inflater = (LayoutInflater) getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.gears_dialog_settings_row, null);
}
OriginPermissions perms = (OriginPermissions) mItems.get(position);
View nameView = row.findViewById(R.id.origin_name);
if (nameView != null) {
TextView originName = (TextView) nameView;
originName.setText(perms.getOrigin());
}
View removeButtonView = row.findViewById(R.id.origin_remove);
if (removeButtonView != null) {
Button removeButton = (Button) removeButtonView;
setRemoveButton(removeButton, perms);
}
for (int i = 0; i < mPermissions.size(); i++) {
PermissionType type = mPermissions.get(i);
int rowRsc = type.getRowRsc();
int allowedButtonRsc = type.getAllowedButtonRsc();
int deniedButtonRsc = type.getDeniedButtonRsc();
View rowView = row.findViewById(rowRsc);
if (rowView != null) {
int perm = perms.getPermission(type);
if (perm != PermissionType.PERMISSION_NOT_SET) {
createAndSetButtonListener(row.findViewById(allowedButtonRsc),
perms, type, PermissionController.ALLOWED_BUTTON);
createAndSetButtonListener(row.findViewById(deniedButtonRsc),
perms, type, PermissionController.DENIED_BUTTON);
rowView.setVisibility(View.VISIBLE);
} else {
rowView.setVisibility(View.GONE);
}
}
}
return row;
}
}
/**
* Utility method used in debug mode to print the list of
* permissions (original values and current values).
*/
public void printPermissions() {
Log.v(TAG, "Original Permissions: ");
for (int i = 0; i < mOriginalPermissions.size(); i++) {
OriginPermissions p = mOriginalPermissions.get(i);
p.print();
}
Log.v(TAG, "Current Permissions: ");
for (int i = 0; i < mSitesPermissions.size(); i++) {
OriginPermissions p = mSitesPermissions.get(i);
p.print();
}
}
/**
* Utility method used by the settings dialog, signaling
* the user the settings have been modified.
* We reflect this by enabling the Allow button (disabled
* by default).
*/
public void signalChanges() {
View view = findViewById(R.id.button_allow);
if (view != null) {
Button button = (Button) view;
button.setEnabled(true);
}
mChanges = true;
}
/**
* Computes the difference between the original permissions and the
* current ones. Returns a json-formatted string.
* It is used by the Settings dialog.
*/
public String computeDiff(boolean modif) {
String ret = null;
try {
JSONObject results = new JSONObject();
JSONArray permissions = new JSONArray();
for (int i = 0; modif && i < mOriginalPermissions.size(); i++) {
OriginPermissions original = mOriginalPermissions.get(i);
OriginPermissions current = mCurrentPermissions.get(i);
JSONObject permission = new JSONObject();
boolean modifications = false;
for (int j = 0; j < mPermissions.size(); j++) {
PermissionType type = mPermissions.get(j);
if (current.getPermission(type) != original.getPermission(type)) {
JSONObject state = new JSONObject();
state.put("permissionState", current.getPermission(type));
permission.put(type.getName(), state);
modifications = true;
}
}
if (modifications) {
permission.put("name", current.getOrigin());
permissions.put(permission);
}
}
results.put("modifiedOrigins", permissions);
ret = results.toString();
} catch (JSONException e) {
Log.e(TAG, "JSON exception ", e);
}
return ret;
}
public String closeDialog(int closingType) {
String ret = null;
switch (closingType) {
case ALWAYS_DENY:
ret = "{\"allow\": false }";
break;
case ALLOW:
ret = computeDiff(true);
break;
case DENY:
ret = computeDiff(false);
break;
}
if (mDebug) {
printPermissions();
}
return ret;
}
}