Android SDK 自带项目GestureBuilderActivity

需要android.permission.WRITE_EXTERNAL_STORAGE权限

<?xml version="1.0" encoding="UTF-8"?> <!-- 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. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.gesture.builder"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application> <activity android:name="GestureBuilderActivity" android:label="@string/application_name" android:icon="@drawable/ic_gesturebuilder"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> <activity android:name="CreateGestureActivity" android:label="@string/label_create_gesture" /> </application> </manifest>

<?xml version="1.0" encoding="utf-8"?> <!-- 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. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1.0" /> <TextView android:id="@android:id/empty" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1.0" android:gravity="center" android:text="@string/gestures_loading" android:textAppearance="?android:attr/textAppearanceMedium" /> <LinearLayout style="@android:style/ButtonBar" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/addButton" android:onClick="addGesture" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:enabled="false" android:text="@string/button_add" /> <Button android:id="@+id/reloadButton" android:onClick="reloadGestures" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:enabled="false" android:text="@string/button_reload" /> <!-- android:onClick="reloadGestures" 制定点击时间处理方法是reloadGestures android:enabled 是否可被点击 style="@android:style/ButtonBar" 制定样式 android:textAppearance 文字外观 "@android:id/list" id为Android默认list id--> </LinearLayout> </LinearLayout>

/* * 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.gesture.builder; import android.app.Dialog; import android.app.AlertDialog; import android.app.ListActivity; import android.os.Bundle; import android.os.AsyncTask; import android.os.Environment; import android.view.View; import android.view.ContextMenu; import android.view.MenuItem; import android.view.LayoutInflater; import android.view.ViewGroup; import android.gesture.GestureLibrary; import android.gesture.Gesture; import android.gesture.GestureLibraries; import android.widget.TextView; import android.widget.EditText; import android.widget.AdapterView; import android.widget.Toast; import android.widget.ArrayAdapter; import android.content.DialogInterface; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.text.TextUtils; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.graphics.drawable.BitmapDrawable; import java.util.Map; import java.util.Collections; import java.util.HashMap; import java.util.Comparator; import java.util.Set; import java.io.File; public class GestureBuilderActivity extends ListActivity { private static final int STATUS_SUCCESS = 0; private static final int STATUS_CANCELLED = 1; private static final int STATUS_NO_STORAGE = 2; private static final int STATUS_NOT_LOADED = 3; private static final int MENU_ID_RENAME = 1; private static final int MENU_ID_REMOVE = 2; private static final int DIALOG_RENAME_GESTURE = 1; private static final int REQUEST_NEW_GESTURE = 1; // Type: long (id) private static final String GESTURES_INFO_ID = "gestures.info_id"; private final File mStoreFile = new File(Environment.getExternalStorageDirectory(), "gestures"); private final Comparator<NamedGesture> mSorter = new Comparator<NamedGesture>() { public int compare(NamedGesture object1, NamedGesture object2) { return object1.name.compareTo(object2.name); } }; private static GestureLibrary sStore; private GesturesAdapter mAdapter; private GesturesLoadTask mTask; private TextView mEmpty; private Dialog mRenameDialog; private EditText mInput; private NamedGesture mCurrentRenameGesture; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.gestures_list); mAdapter = new GesturesAdapter(this); setListAdapter(mAdapter); //设置ListAdapter为@android:id/list if (sStore == null) { sStore = GestureLibraries.fromFile(mStoreFile); } mEmpty = (TextView) findViewById(android.R.id.empty); loadGestures(); //注册环境Menu事件为ListView @android:id/list registerForContextMenu(getListView()); } static GestureLibrary getStore() { return sStore; } //点击Reload按钮时间,配置在资源gestures_list.xml @SuppressWarnings({"UnusedDeclaration"}) public void reloadGestures(View v) { loadGestures(); } //点击add getsture按钮时间,配置在资源gestures_list. @SuppressWarnings({"UnusedDeclaration"}) public void addGesture(View v) { Intent intent = new Intent(this, CreateGestureActivity.class); startActivityForResult(intent, REQUEST_NEW_GESTURE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { switch (requestCode) { case REQUEST_NEW_GESTURE: loadGestures(); break; } } } private void loadGestures() { //搜寻未完成则取消,从新运行 if (mTask != null && mTask.getStatus() != GesturesLoadTask.Status.FINISHED) { mTask.cancel(true); } mTask = (GesturesLoadTask) new GesturesLoadTask().execute(); } @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); //销毁时如果正在重命名Gesture保存状态 if (mCurrentRenameGesture != null) { outState.putLong(GESTURES_INFO_ID, mCurrentRenameGesture.gesture.getID()); } } @Override protected void onRestoreInstanceState(Bundle state) { super.onRestoreInstanceState(state); //重新创建时恢复状态 long id = state.getLong(GESTURES_INFO_ID, -1); if (id != -1) { final Set<String> entries = sStore.getGestureEntries(); out: for (String name : entries) { for (Gesture gesture : sStore.getGestures(name)) { if (gesture.getID() == id) { mCurrentRenameGesture = new NamedGesture(); mCurrentRenameGesture.name = name; mCurrentRenameGesture.gesture = gesture; break out; } } } } } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); //获取ContextMenu点击点所在的view AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; 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(); //获取ContextMenu点击点所在的view的TAG final NamedGesture gesture = (NamedGesture) menuInfo.targetView.getTag(); switch (item.getItemId()) { case MENU_ID_RENAME: renameGesture(gesture); return true; case MENU_ID_REMOVE: deleteGesture(gesture); return true; } return super.onContextItemSelected(item); } private void renameGesture(NamedGesture gesture) { mCurrentRenameGesture = gesture; //系统自动调用onCreateDialog->onPrepareDialog 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); //为Dialog中EditText赋值 if (id == DIALOG_RENAME_GESTURE) { mInput.setText(mCurrentRenameGesture.name); } } private Dialog createRenameDialog() { final View layout = View.inflate(this, R.layout.dialog_rename, null); mInput = (EditText) layout.findViewById(R.id.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); //可点击back回退 builder.setOnCancelListener(new Dialog.OnCancelListener() {//back回退时间监听 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 NamedGesture renameGesture = mCurrentRenameGesture; final 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 NamedGesture gesture = adapter.getItem(i); if (gesture.gesture.getID() == renameGesture.gesture.getID()) { sStore.removeGesture(gesture.name, gesture.gesture); gesture.name = mInput.getText().toString(); sStore.addGesture(gesture.name, gesture.gesture); break; } } //更新ListView adapter.notifyDataSetChanged(); } mCurrentRenameGesture = null; } private void cleanupRenameDialog() { if (mRenameDialog != null) { mRenameDialog.dismiss(); mRenameDialog = null; } mCurrentRenameGesture = null; } private void deleteGesture(NamedGesture gesture) { sStore.removeGesture(gesture.name, gesture.gesture); sStore.save(); //保存292行 没有 sStore.save() 所以当修改后,重新Reload时原先修改会丢失 final GesturesAdapter adapter = mAdapter; adapter.setNotifyOnChange(false); adapter.remove(gesture); adapter.sort(mSorter); //排序 checkForEmpty(); adapter.notifyDataSetChanged(); //更新 Toast.makeText(this, R.string.gestures_delete_success, Toast.LENGTH_SHORT).show(); } private class GesturesLoadTask extends AsyncTask<Void, NamedGesture, Integer> { private int mThumbnailSize; private int mThumbnailInset; private int mPathColor; //onPreExecute->doInBackground(onProgressUpdate)->onPostExecute @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); findViewById(R.id.addButton).setEnabled(false); findViewById(R.id.reloadButton).setEnabled(false); mAdapter.setNotifyOnChange(false); mAdapter.clear(); } @Override protected Integer doInBackground(Void... params) { if (isCancelled()) return STATUS_CANCELLED; //是否有存储卡 if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { return STATUS_NO_STORAGE; } final GestureLibrary store = sStore; if (store.load()) { for (String name : store.getGestureEntries()) { if (isCancelled()) break; for (Gesture gesture : store.getGestures(name)) { //把Gesture转化为Bitmap final Bitmap bitmap = gesture.toBitmap(mThumbnailSize, mThumbnailSize, mThumbnailInset, mPathColor); final NamedGesture namedGesture = new NamedGesture(); namedGesture.gesture = gesture; namedGesture.name = name; //ListView mAdapter.addBitmap(namedGesture.gesture.getID(), bitmap); publishProgress(namedGesture); } } return STATUS_SUCCESS; } return STATUS_NOT_LOADED; } @Override protected void onProgressUpdate(NamedGesture... values) { super.onProgressUpdate(values); final GesturesAdapter adapter = mAdapter; adapter.setNotifyOnChange(false); for (NamedGesture gesture : values) { adapter.add(gesture); } adapter.sort(mSorter); adapter.notifyDataSetChanged(); } @Override protected void onPostExecute(Integer result) { super.onPostExecute(result); if (result == STATUS_NO_STORAGE) { getListView().setVisibility(View.GONE); mEmpty.setVisibility(View.VISIBLE); mEmpty.setText(getString(R.string.gestures_error_loading, mStoreFile.getAbsolutePath())); } else { findViewById(R.id.addButton).setEnabled(true); findViewById(R.id.reloadButton).setEnabled(true); checkForEmpty(); } } } static class NamedGesture { String name; Gesture gesture; } private class GesturesAdapter extends ArrayAdapter<NamedGesture> { private final LayoutInflater mInflater; //创建线程安全的HashMap 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_item, parent, false); } final NamedGesture gesture = getItem(position); final TextView label = (TextView) convertView; label.setTag(gesture); //设置目标TAG,在211行有使用 有保存数据的作用 label.setText(gesture.name); //在TextView中放入图片资源显示setCompoundDrawablesWithIntrinsicBounds label.setCompoundDrawablesWithIntrinsicBounds(mThumbnails.get(gesture.gesture.getID()), null, null, null); return convertView; } } }

/* * 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.gesture.builder; import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.view.View; import android.view.MotionEvent; import android.gesture.GestureOverlayView; import android.gesture.Gesture; import android.gesture.GestureLibrary; import android.widget.TextView; import android.widget.Toast; import java.io.File; public class CreateGestureActivity extends Activity { private static final float LENGTH_THRESHOLD = 120.0f; private Gesture mGesture; private View mDoneButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.create_gesture); mDoneButton = findViewById(R.id.done); GestureOverlayView overlay = (GestureOverlayView) findViewById(R.id.gestures_overlay); overlay.addOnGestureListener(new GesturesProcessor()); //手势事件监听 } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if (mGesture != null) { //保存mGesture临时状态 outState.putParcelable("gesture", mGesture); } } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); mGesture = savedInstanceState.getParcelable("gesture"); if (mGesture != null) { final GestureOverlayView overlay = (GestureOverlayView) findViewById(R.id.gestures_overlay); //重置GestureOverlayView,异步 overlay.post(new Runnable() { public void run() { overlay.setGesture(mGesture); } }); mDoneButton.setEnabled(true); } } @SuppressWarnings({"UnusedDeclaration"}) public void addGesture(View v) { if (mGesture != null) { final TextView input = (TextView) findViewById(R.id.gesture_name); final CharSequence name = input.getText(); if (name.length() == 0) { input.setError(getString(R.string.error_missing_name)); return; } final GestureLibrary store = GestureBuilderActivity.getStore(); store.addGesture(name.toString(), mGesture); store.save(); setResult(RESULT_OK); final String path = new File(Environment.getExternalStorageDirectory(), "gestures").getAbsolutePath(); //getAbsolutePath获取绝对路径 //getString(R.string.save_success, path) 已path代替R.string.save_success中参数 Toast.makeText(this, getString(R.string.save_success, path), Toast.LENGTH_LONG).show(); } else { setResult(RESULT_CANCELED); } finish(); } @SuppressWarnings({"UnusedDeclaration"}) public void cancelGesture(View v) { setResult(RESULT_CANCELED); finish(); } private class GesturesProcessor implements GestureOverlayView.OnGestureListener { public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) { mDoneButton.setEnabled(false); mGesture = null; } public void onGesture(GestureOverlayView overlay, MotionEvent event) { } public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) { mGesture = overlay.getGesture(); if (mGesture.getLength() < LENGTH_THRESHOLD) { //小于120长度则清空 overlay.clear(false); } mDoneButton.setEnabled(true); } public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) { } } }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值