| /* |
| * 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<OriginPermissions> mSitesPermissions = null; |
| private Vector<OriginPermissions> mOriginalPermissions = null; |
| private Vector<OriginPermissions> mCurrentPermissions = null; |
| |
| private Vector<PermissionType> 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<PermissionType>(); |
| 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<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; |
| 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; |
| } |
| |
| } |