/* * 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.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; 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.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.CheckBox; 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.Permission; 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 mSitesPermissions = null; private Vector mOriginalPermissions = null; private Vector mCurrentPermissions = null; private Vector mPermissions; private static final int CONFIRMATION_REMOVE_DIALOG = 1; // 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; SettingsAdapter mListAdapter; public GearsSettingsDialog(Activity activity, Handler handler, String arguments) { super (activity, handler, arguments); activity.setContentView(R.layout.gears_settings); } public void setup() { // First let's add the permissions' resources LOCAL_STORAGE.setResources(R.string.settings_storage_title, R.string.settings_storage_subtitle_on, R.string.settings_storage_subtitle_off); LOCATION_DATA.setResources(R.string.settings_location_title, R.string.settings_location_subtitle_on, R.string.settings_location_subtitle_off); // add the permissions to the list of permissions. mPermissions = new Vector(); mPermissions.add(LOCAL_STORAGE); mPermissions.add(LOCATION_DATA); OriginPermissions.setListener(this); setupDialog(); // 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(); mOriginalPermissions = new Vector(); 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)mSitesPermissions.clone(); View listView = findViewById(R.id.sites_list); if (listView != null) { ListView list = (ListView) listView; mListAdapter = new SettingsAdapter(mActivity, mSitesPermissions); list.setAdapter(mListAdapter); list.setScrollBarStyle(android.view.View.SCROLLBARS_OUTSIDE_INSET); list.setOnItemClickListener(mListAdapter); } if (mDebug) { printPermissions(); } } private void setMainTitle() { String windowTitle = mActivity.getString(R.string.pref_extras_gears_settings); mActivity.setTitle(windowTitle); } public void setupDialog() { setMainTitle(); } /** * GearsPermissions.PermissionsChangesListener delegate */ public boolean setPermission(PermissionType type, int perm) { if (mChanges == false) { mChanges = true; } return mChanges; } public boolean handleBackButton() { return mListAdapter.backButtonPressed(); } /** * We use this to create a confirmation dialog when the user * clicks on "remove this site from gears" */ public Dialog onCreateDialog(int id) { return new AlertDialog.Builder(mActivity) .setTitle(R.string.settings_confirmation_remove_title) .setMessage(R.string.settings_confirmation_remove) .setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() { public void onClick(DialogInterface dlg, int which) { mListAdapter.removeCurrentSite(); } }) .setNegativeButton(android.R.string.cancel, null) .setIcon(android.R.drawable.ic_dialog_alert) .create(); } /** * Adapter class for the list view in the settings dialog * * We first display a list of all the origins (sites), or * a message saying that no permission is set if the list is empty. * When the user click on one of the origin, we then display * the list of the permissions existing for that origin. * Each permission can be either allowed or denied by clicking * on the checkbox. * The last row is a special case, allowing to remove the entire origin. */ class SettingsAdapter extends BaseAdapter implements AdapterView.OnItemClickListener { private Activity mContext; private List mItems; private OriginPermissions mCurrentSite; private Vector mCurrentPermissions; private int MAX_ROW_HEIGHT = 64; SettingsAdapter(Activity context, List items) { mContext = context; mItems = items; mCurrentSite = null; } public int getCount() { if (mCurrentSite == null) { int size = mItems.size(); if (size == 0) { return 1; } else { return size; } } return mCurrentPermissions.size() + 1; } public long getItemId(int position) { return position; } private String shortName(String url) { // We remove the http and https prefix if (url.startsWith("http://")) { return url.substring(7); } if (url.startsWith("https://")) { return url.substring(8); } return url; } public Object getItem(int position) { if (mCurrentSite == null) { if (mItems.size() == 0) { return null; } else { return mItems.get(position); } } return mCurrentPermissions.get(position); } 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_settings_row, null); } row.setMinimumHeight(MAX_ROW_HEIGHT); if (mCurrentSite == null) { if (mItems.size() == 0) { hideView(row, R.id.title); hideView(row, R.id.subtitle); hideView(row, R.id.checkbox); hideView(row, R.id.icon); setText(row, R.id.info, R.string.settings_empty); } else { hideView(row, R.id.subtitle); hideView(row, R.id.info); hideView(row, R.id.checkbox); OriginPermissions perms = (OriginPermissions) mItems.get(position); setText(row, R.id.title, shortName(perms.getOrigin())); showView(row, R.id.icon); } } else { if (position == getCount() - 1) { // last position: "remove this site from gears" hideView(row, R.id.subtitle); hideView(row, R.id.info); hideView(row, R.id.checkbox); hideView(row, R.id.icon); setText(row, R.id.title, R.string.settings_remove_site); } else { hideView(row, R.id.info); hideView(row, R.id.icon); showView(row, R.id.checkbox); PermissionType type = (PermissionType) mCurrentPermissions.get(position); setText(row, R.id.title, type.getTitleRsc()); View checkboxView = row.findViewById(R.id.checkbox); if (checkboxView != null) { CheckBox checkbox = (CheckBox) checkboxView; int perm = mCurrentSite.getPermission(type); if (perm == PermissionType.PERMISSION_DENIED) { setText(row, R.id.subtitle, type.getSubtitleOffRsc()); checkbox.setChecked(false); } else { setText(row, R.id.subtitle, type.getSubtitleOnRsc()); checkbox.setChecked(true); } } } } return row; } public void removeCurrentSite() { mCurrentSite.setPermission(LOCAL_STORAGE, PermissionType.PERMISSION_NOT_SET); mCurrentSite.setPermission(LOCATION_DATA, PermissionType.PERMISSION_NOT_SET); mSitesPermissions.remove(mCurrentSite); mCurrentSite = null; setMainTitle(); notifyDataSetChanged(); } public void onItemClick(AdapterView parent, View view, int position, long id) { if (mItems.size() == 0) { return; } if (mCurrentSite == null) { mCurrentSite = (OriginPermissions) mItems.get(position); mCurrentPermissions = new Vector(); for (int i = 0; i < mPermissions.size(); i++) { PermissionType type = mPermissions.get(i); int perm = mCurrentSite.getPermission(type); if (perm != PermissionType.PERMISSION_NOT_SET) { mCurrentPermissions.add(type); } } mContext.setTitle(shortName(mCurrentSite.getOrigin())); } else { if (position == getCount() - 1) { // last item (remove site) // Ask the user to confirm // If yes, removeCurrentSite() will be called via the dialog callback. mActivity.showDialog(CONFIRMATION_REMOVE_DIALOG); } else { PermissionType type = (PermissionType) mCurrentPermissions.get(position); if (mCurrentSite.getPermission(type) == PermissionType.PERMISSION_ALLOWED) { mCurrentSite.setPermission(type, PermissionType.PERMISSION_DENIED); } else { mCurrentSite.setPermission(type, PermissionType.PERMISSION_ALLOWED); } } } notifyDataSetChanged(); } public boolean backButtonPressed() { if (mCurrentSite != null) { // we intercept the back button mCurrentSite = null; setMainTitle(); notifyDataSetChanged(); return true; } return false; } } /** * 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(); } } /** * 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 = computeDiff(mChanges); if (mDebug) { printPermissions(); } return ret; } }