mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-20 03:08:19 +00:00
488 lines
16 KiB
Java
488 lines
16 KiB
Java
/*
|
|
* Copyright (C) 2009 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.launcher;
|
|
|
|
import android.app.ListActivity;
|
|
import android.app.Dialog;
|
|
import android.app.AlertDialog;
|
|
import android.os.Bundle;
|
|
import android.os.AsyncTask;
|
|
import android.widget.ArrayAdapter;
|
|
import android.widget.TextView;
|
|
import android.widget.AdapterView;
|
|
import android.widget.Toast;
|
|
import android.widget.EditText;
|
|
import android.widget.BaseAdapter;
|
|
import android.widget.CheckBox;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.SharedPreferences;
|
|
import android.content.res.Resources;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.view.LayoutInflater;
|
|
import android.view.ContextMenu;
|
|
import android.view.MenuItem;
|
|
import android.gesture.GestureLibrary;
|
|
import android.gesture.Gesture;
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.graphics.drawable.BitmapDrawable;
|
|
import android.text.TextUtils;
|
|
import android.database.DataSetObserver;
|
|
|
|
import java.util.Comparator;
|
|
import java.util.HashMap;
|
|
import java.util.Collections;
|
|
import java.util.Map;
|
|
|
|
public class GesturesActivity extends ListActivity implements AdapterView.OnItemClickListener {
|
|
private static final int MENU_ID_RENAME = 1;
|
|
private static final int MENU_ID_REMOVE = 2;
|
|
|
|
private static final int DIALOG_RENAME_GESTURE = 1;
|
|
|
|
static final String PREFERENCES_NAME = "gestures";
|
|
static final String PREFERENCES_HOME_KEY = "gestures.home";
|
|
|
|
// Type: long (id)
|
|
private static final String GESTURES_INFO_ID = "gestures.info_id";
|
|
|
|
private final Comparator<ApplicationInfo> mSorter =
|
|
new LauncherModel.ApplicationInfoComparator();
|
|
|
|
private GesturesAdapter mAdapter;
|
|
private GestureLibrary mStore;
|
|
private GesturesLoadTask mTask;
|
|
private TextView mEmpty;
|
|
|
|
private Dialog mRenameDialog;
|
|
private EditText mInput;
|
|
private ApplicationInfo mCurrentRenameInfo;
|
|
private SharedPreferences mPreferences;
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
|
|
setContentView(R.layout.gestures_settings);
|
|
|
|
mAdapter = new GesturesAdapter(this);
|
|
setListAdapter(new GesturesSettingsAdapter(mAdapter));
|
|
getListView().setOnItemClickListener(this);
|
|
|
|
mStore = Launcher.getGestureLibrary();
|
|
mEmpty = (TextView) findViewById(android.R.id.empty);
|
|
mTask = (GesturesLoadTask) new GesturesLoadTask().execute();
|
|
|
|
registerForContextMenu(getListView());
|
|
|
|
mPreferences = getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE);
|
|
}
|
|
|
|
@Override
|
|
protected void onDestroy() {
|
|
super.onDestroy();
|
|
|
|
if (mTask != null && mTask.getStatus() != GesturesLoadTask.Status.FINISHED) {
|
|
mTask.cancel(true);
|
|
mTask = null;
|
|
}
|
|
|
|
cleanupRenameDialog();
|
|
}
|
|
|
|
private void checkForEmpty() {
|
|
if (mAdapter.getCount() == 0) {
|
|
mEmpty.setText(R.string.gestures_empty);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onSaveInstanceState(Bundle outState) {
|
|
super.onSaveInstanceState(outState);
|
|
|
|
if (mCurrentRenameInfo != null) {
|
|
outState.putLong(GESTURES_INFO_ID, mCurrentRenameInfo.id);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onRestoreInstanceState(Bundle state) {
|
|
super.onRestoreInstanceState(state);
|
|
|
|
long id = state.getLong(GESTURES_INFO_ID, -1);
|
|
if (id != -1) {
|
|
mCurrentRenameInfo = Launcher.getModel().queryGesture(this, String.valueOf(id));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onCreateContextMenu(ContextMenu menu, View v,
|
|
ContextMenu.ContextMenuInfo menuInfo) {
|
|
|
|
super.onCreateContextMenu(menu, v, menuInfo);
|
|
|
|
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
|
|
if (info.position > 2) {
|
|
menu.setHeaderTitle(((TextView) info.targetView).getText());
|
|
|
|
menu.add(0, MENU_ID_RENAME, 0, R.string.gestures_rename);
|
|
menu.add(0, MENU_ID_REMOVE, 0, R.string.gestures_delete);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onContextItemSelected(MenuItem item) {
|
|
final AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo)
|
|
item.getMenuInfo();
|
|
final ApplicationInfo info = (ApplicationInfo) menuInfo.targetView.getTag();
|
|
|
|
switch (item.getItemId()) {
|
|
case MENU_ID_RENAME:
|
|
renameGesture(info);
|
|
return true;
|
|
case MENU_ID_REMOVE:
|
|
deleteGesture(info);
|
|
return true;
|
|
}
|
|
|
|
return super.onContextItemSelected(item);
|
|
}
|
|
|
|
private void renameGesture(ApplicationInfo info) {
|
|
mCurrentRenameInfo = info;
|
|
showDialog(DIALOG_RENAME_GESTURE);
|
|
}
|
|
|
|
@Override
|
|
protected Dialog onCreateDialog(int id) {
|
|
if (id == DIALOG_RENAME_GESTURE) {
|
|
return createRenameDialog();
|
|
}
|
|
return super.onCreateDialog(id);
|
|
}
|
|
|
|
@Override
|
|
protected void onPrepareDialog(int id, Dialog dialog) {
|
|
super.onPrepareDialog(id, dialog);
|
|
if (id == DIALOG_RENAME_GESTURE && mCurrentRenameInfo != null) {
|
|
mInput.setText(mCurrentRenameInfo.title);
|
|
}
|
|
}
|
|
|
|
private Dialog createRenameDialog() {
|
|
final View layout = View.inflate(this, R.layout.rename_folder, null);
|
|
mInput = (EditText) layout.findViewById(R.id.folder_name);
|
|
((TextView) layout.findViewById(R.id.label)).setText(R.string.gestures_rename_label);
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
builder.setIcon(0);
|
|
builder.setTitle(getString(R.string.gestures_rename_title));
|
|
builder.setCancelable(true);
|
|
builder.setOnCancelListener(new Dialog.OnCancelListener() {
|
|
public void onCancel(DialogInterface dialog) {
|
|
cleanupRenameDialog();
|
|
}
|
|
});
|
|
builder.setNegativeButton(getString(R.string.cancel_action),
|
|
new Dialog.OnClickListener() {
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
cleanupRenameDialog();
|
|
}
|
|
}
|
|
);
|
|
builder.setPositiveButton(getString(R.string.rename_action),
|
|
new Dialog.OnClickListener() {
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
changeGestureName();
|
|
}
|
|
}
|
|
);
|
|
builder.setView(layout);
|
|
return builder.create();
|
|
}
|
|
|
|
private void changeGestureName() {
|
|
final String name = mInput.getText().toString();
|
|
if (!TextUtils.isEmpty(name)) {
|
|
final ApplicationInfo renameInfo = mCurrentRenameInfo;
|
|
final GesturesActivity.GesturesAdapter adapter = mAdapter;
|
|
final int count = adapter.getCount();
|
|
|
|
// Simple linear search, there should not be enough items to warrant
|
|
// a more sophisticated search
|
|
for (int i = 0; i < count; i++) {
|
|
final ApplicationInfo info = adapter.getItem(i);
|
|
if (info.id == renameInfo.id) {
|
|
info.title = mInput.getText();
|
|
LauncherModel.updateGestureInDatabase(this, info);
|
|
break;
|
|
}
|
|
}
|
|
|
|
adapter.notifyDataSetChanged();
|
|
}
|
|
mCurrentRenameInfo = null;
|
|
}
|
|
|
|
private void cleanupRenameDialog() {
|
|
if (mRenameDialog != null) {
|
|
mRenameDialog.dismiss();
|
|
mRenameDialog = null;
|
|
}
|
|
mCurrentRenameInfo = null;
|
|
}
|
|
|
|
private void deleteGesture(ApplicationInfo info) {
|
|
mStore.removeEntry(String.valueOf(info.id));
|
|
// TODO: On a thread?
|
|
mStore.save();
|
|
|
|
final GesturesActivity.GesturesAdapter adapter = mAdapter;
|
|
adapter.setNotifyOnChange(false);
|
|
adapter.remove(info);
|
|
adapter.sort(mSorter);
|
|
checkForEmpty();
|
|
adapter.notifyDataSetChanged();
|
|
|
|
LauncherModel.deleteGestureFromDatabase(this, info);
|
|
|
|
Toast.makeText(this, R.string.gestures_delete_success, Toast.LENGTH_SHORT).show();
|
|
}
|
|
|
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
|
if (position == 1) {
|
|
final CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox);
|
|
checkBox.toggle();
|
|
mPreferences.edit().putBoolean(PREFERENCES_HOME_KEY, checkBox.isChecked()).commit();
|
|
}
|
|
}
|
|
|
|
private class GesturesLoadTask extends AsyncTask<Void, ApplicationInfo, Boolean> {
|
|
private int mThumbnailSize;
|
|
private int mThumbnailInset;
|
|
private int mPathColor;
|
|
|
|
@Override
|
|
protected void onPreExecute() {
|
|
super.onPreExecute();
|
|
|
|
final Resources resources = getResources();
|
|
mPathColor = resources.getColor(R.color.gesture_color);
|
|
mThumbnailInset = (int) resources.getDimension(R.dimen.gesture_thumbnail_inset);
|
|
mThumbnailSize = (int) resources.getDimension(R.dimen.gesture_thumbnail_size);
|
|
}
|
|
|
|
protected Boolean doInBackground(Void... params) {
|
|
if (isCancelled()) return Boolean.FALSE;
|
|
|
|
final GestureLibrary store = mStore;
|
|
|
|
if (store.load()) {
|
|
final LauncherModel model = Launcher.getModel();
|
|
|
|
for (String name : store.getGestureEntries()) {
|
|
if (isCancelled()) break;
|
|
|
|
final Gesture gesture = store.getGestures(name).get(0);
|
|
final Bitmap bitmap = gesture.toBitmap(mThumbnailSize, mThumbnailSize,
|
|
mThumbnailInset, mPathColor);
|
|
final ApplicationInfo info = model.queryGesture(GesturesActivity.this, name);
|
|
|
|
mAdapter.addBitmap(info.id, bitmap);
|
|
publishProgress(info);
|
|
}
|
|
|
|
return Boolean.TRUE;
|
|
}
|
|
|
|
return Boolean.FALSE;
|
|
}
|
|
|
|
@Override
|
|
protected void onProgressUpdate(ApplicationInfo... values) {
|
|
super.onProgressUpdate(values);
|
|
|
|
final GesturesActivity.GesturesAdapter adapter = mAdapter;
|
|
adapter.setNotifyOnChange(false);
|
|
|
|
for (ApplicationInfo info : values) {
|
|
adapter.add(info);
|
|
}
|
|
|
|
adapter.sort(mSorter);
|
|
adapter.notifyDataSetChanged();
|
|
}
|
|
|
|
@Override
|
|
protected void onPostExecute(Boolean aBoolean) {
|
|
super.onPostExecute(aBoolean);
|
|
checkForEmpty();
|
|
}
|
|
}
|
|
|
|
private class GesturesAdapter extends ArrayAdapter<ApplicationInfo> {
|
|
private final LayoutInflater mInflater;
|
|
private final Map<Long, Drawable> mThumbnails = Collections.synchronizedMap(
|
|
new HashMap<Long, Drawable>());
|
|
|
|
public GesturesAdapter(Context context) {
|
|
super(context, 0);
|
|
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
}
|
|
|
|
void addBitmap(Long id, Bitmap bitmap) {
|
|
mThumbnails.put(id, new BitmapDrawable(bitmap));
|
|
}
|
|
|
|
@Override
|
|
public View getView(int position, View convertView, ViewGroup parent) {
|
|
if (convertView == null) {
|
|
convertView = mInflater.inflate(R.layout.gestures_settings_item, parent, false);
|
|
}
|
|
|
|
final ApplicationInfo info = getItem(position);
|
|
final TextView label = (TextView) convertView;
|
|
|
|
label.setTag(info);
|
|
label.setText(info.title);
|
|
label.setCompoundDrawablesWithIntrinsicBounds(info.icon, null,
|
|
mThumbnails.get(info.id), null);
|
|
|
|
return convertView;
|
|
}
|
|
}
|
|
|
|
private class GesturesSettingsAdapter extends BaseAdapter {
|
|
private static final int FIXED_CHILDREN_COUNT = 3;
|
|
|
|
private static final int VIEW_TYPE_SEPARATOR = 0;
|
|
private static final int VIEW_TYPE_CHECKBOX = 1;
|
|
|
|
private final GesturesAdapter mAdapter;
|
|
private final LayoutInflater mInflater;
|
|
|
|
public GesturesSettingsAdapter(GesturesAdapter adapter) {
|
|
mAdapter = adapter;
|
|
mInflater = adapter.mInflater;
|
|
adapter.registerDataSetObserver(new DataSetObserver() {
|
|
@Override
|
|
public void onChanged() {
|
|
notifyDataSetChanged();
|
|
}
|
|
|
|
@Override
|
|
public void onInvalidated() {
|
|
notifyDataSetInvalidated();
|
|
}
|
|
});
|
|
}
|
|
|
|
public int getCount() {
|
|
return FIXED_CHILDREN_COUNT + mAdapter.getCount();
|
|
}
|
|
|
|
public Object getItem(int position) {
|
|
if (position < FIXED_CHILDREN_COUNT) {
|
|
return String.valueOf(position);
|
|
}
|
|
return mAdapter.getItem(position - FIXED_CHILDREN_COUNT);
|
|
}
|
|
|
|
public long getItemId(int position) {
|
|
return position;
|
|
}
|
|
|
|
@Override
|
|
public int getItemViewType(int position) {
|
|
if (position < FIXED_CHILDREN_COUNT) {
|
|
switch (position) {
|
|
case 0:
|
|
case 2:
|
|
return VIEW_TYPE_SEPARATOR;
|
|
case 1:
|
|
return VIEW_TYPE_CHECKBOX;
|
|
}
|
|
}
|
|
return 2 + super.getItemViewType(position);
|
|
}
|
|
|
|
@Override
|
|
public int getViewTypeCount() {
|
|
return 2 + mAdapter.getViewTypeCount();
|
|
}
|
|
|
|
@Override
|
|
public boolean areAllItemsEnabled() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean isEnabled(int position) {
|
|
return position != 0 && position != 2;
|
|
}
|
|
|
|
public View getView(int position, View convertView, ViewGroup parent) {
|
|
if (position < FIXED_CHILDREN_COUNT) {
|
|
// NOTE: Don't bother with ViewHolders here, we only have 3 items and
|
|
// the list is likely to not be very long
|
|
switch (position) {
|
|
case 0:
|
|
convertView = createHeader(convertView, parent,
|
|
R.string.gestures_group_settings);
|
|
break;
|
|
case 1:
|
|
convertView = createSetting(convertView, parent,
|
|
R.string.gestures_preference_hotkey_title,
|
|
R.string.gestures_preference_hotkey_summary);
|
|
break;
|
|
case 2:
|
|
convertView = createHeader(convertView, parent,
|
|
R.string.gestures_group_gestures);
|
|
break;
|
|
}
|
|
return convertView;
|
|
}
|
|
return mAdapter.getView(position - FIXED_CHILDREN_COUNT, convertView, parent);
|
|
}
|
|
|
|
private View createSetting(View convertView, ViewGroup parent,
|
|
int title, int summary) {
|
|
|
|
if (convertView == null) {
|
|
convertView = mInflater.inflate(R.layout.list_checkbox_2lines, parent, false);
|
|
}
|
|
|
|
((TextView) convertView.findViewById(R.id.title)).setText(title);
|
|
((TextView) convertView.findViewById(R.id.summary)).setText(summary);
|
|
((CheckBox) convertView.findViewById(R.id.checkbox)).setChecked(
|
|
mPreferences.getBoolean(PREFERENCES_HOME_KEY, false));
|
|
|
|
return convertView;
|
|
}
|
|
|
|
private View createHeader(View convertView, ViewGroup parent, int text) {
|
|
if (convertView == null) {
|
|
convertView = mInflater.inflate(R.layout.list_category, parent, false);
|
|
}
|
|
((TextView) convertView).setText(text);
|
|
return convertView;
|
|
}
|
|
}
|
|
}
|