/* * Copyright (C) 2009 Apps Organizer * * This file is part of Apps Organizer * * Apps Organizer is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Apps Organizer is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Apps Organizer. If not, see <http://www.gnu.org/licenses/>. */ package com.google.code.appsorganizer.shortcut; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.database.Cursor; import android.database.MatrixCursor; import android.database.MergeCursor; import android.database.AbstractCursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Looper; import android.os.MessageQueue; import android.preference.PreferenceManager; import android.util.DisplayMetrics; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Gravity; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnCreateContextMenuListener; import android.view.ViewGroup; import android.view.Window; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.GridView; import android.widget.RelativeLayout; import android.widget.SimpleCursorAdapter; import android.widget.TextView; import android.widget.Toast; import com.google.code.appsorganizer.ApplicationContextMenuManager; import com.google.code.appsorganizer.BugReportActivity; import com.google.code.appsorganizer.ChooseAppsDialogCreator; import com.google.code.appsorganizer.ChooseLabelDialogCreator; import com.google.code.appsorganizer.R; import com.google.code.appsorganizer.db.AppCacheDao; import com.google.code.appsorganizer.db.DatabaseHelperBasic; import com.google.code.appsorganizer.db.LabelDao; import com.google.code.appsorganizer.dialogs.ActivityWithDialog; import com.google.code.appsorganizer.dialogs.OnOkClickListener; import com.google.code.appsorganizer.model.Label; public class LabelShortcut extends ActivityWithDialog { private static final String ONLY_STARRED_PREF = "onlyStarred"; public static final long ALL_LABELS_ID = -2l; public static final long ALL_STARRED_ID = -3l; public static final long OTHER_APPS = -4l; public static final String LABEL_ID = "com.example.android.apis.app.LauncherShortcuts"; private DatabaseHelperBasic dbHelper; private long labelId; private boolean allLabelsSelected; private GridView grid; private CheckBox starCheck; private TextView titleView; private ChooseAppsDialogCreator chooseAppsDialogCreator; private ChooseLabelDialogCreator chooseLabelDialog; public static boolean firstTime = true; private SharedPreferences prefs; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); prefs = PreferenceManager.getDefaultSharedPreferences(this); OnOkClickListener onOkClickListener = new OnOkClickListener() { private static final long serialVersionUID = 1L; public void onClick(CharSequence charSequence, DialogInterface dialog, int which) { requeryCursor(); } }; chooseAppsDialogCreator = new ChooseAppsDialogCreator(getGenericDialogManager(), onOkClickListener); chooseLabelDialog = new ChooseLabelDialogCreator(getGenericDialogManager(), onOkClickListener); BugReportActivity.registerExceptionHandler(this); requestWindowFeature(Window.FEATURE_NO_TITLE); createGrid(); final Intent intent = getIntent(); labelId = intent.getLongExtra(LABEL_ID, 2);// ALL_STARRED_ID); allLabelsSelected = labelId == ALL_LABELS_ID; } @Override protected void onResume() { super.onResume(); // Debug.startMethodTracing("grid1"); reloadDataExternalThread(); // new Thread() { // @Override // public void run() { // try { // Thread.sleep(5000); // } catch (InterruptedException e) { // e.printStackTrace(); // } // Debug.stopMethodTracing(); // } // }.start(); } @Override protected void onDestroy() { super.onDestroy(); closeCurrentCursor(); if (dbHelper != null) { dbHelper.close(); dbHelper = null; } } private void closeCurrentCursor() { if (cursorAdapter != null) { Cursor cursor = cursorAdapter.getCursor(); if (cursor != null && !cursor.isClosed()) { cursor.close(); } } } private Cursor reloadGrid() { if (labelId == ALL_LABELS_ID) { Cursor cursor = getDbHelper().getDb().query(LabelDao.TABLE_NAME, new String[] { LabelDao.ID_COL_NAME, LabelDao.LABEL_COL_NAME, LabelDao.ICON_COL_NAME, LabelDao.IMAGE_COL_NAME }, null, null, null, null, ("upper(" + LabelDao.LABEL_COL_NAME + ")")); MatrixCursor otherAppsCursor = new MatrixCursor(LabelDao.COLS_STRING, 1); otherAppsCursor.addRow(new Object[] { OTHER_APPS, getText(R.string.other_label).toString(), 0, null }); MergeCursor m = new MergeCursor(new Cursor[] { cursor, otherAppsCursor }); return m; } else { Cursor tmpCursor; if (labelId == ALL_STARRED_ID) { tmpCursor = getDbHelper().getDb().rawQuery( "select _id, label, image, package, name from apps where starred = 1 and disabled = 0 order by upper(label)", null); } else if (labelId == OTHER_APPS) { tmpCursor = getDbHelper().getDb().rawQuery( "select a._id, a.label, a.image, a.package, a.name from apps a where a.disabled = 0 and not exists(" + "select 1 from apps_labels al where a.name = al.app and a.package = al.package) order by upper(a.label)", null); } else { boolean starredFirst = prefs.getBoolean("starred_first", true); boolean onlyStarred = prefs.getBoolean(ONLY_STARRED_PREF, false); tmpCursor = AppCacheDao.getAppsOfLabelCursor(getDbHelper().getDb(), labelId, starredFirst, onlyStarred); if (onlyStarred && tmpCursor.getCount() == 0) { Toast.makeText(this, R.string.starred_warning, Toast.LENGTH_LONG).show(); } } return tmpCursor; } } private String retrieveTitle() { if (labelId == ALL_LABELS_ID) { return getString(R.string.all_labels); } else if (labelId == ALL_STARRED_ID) { return getString(R.string.Starred_apps); } else if (labelId == OTHER_APPS) { return getString(R.string.other_label); } else { Cursor c = getDbHelper().getDb().query(LabelDao.TABLE_NAME, new String[] { LabelDao.LABEL_COL_NAME }, LabelDao.ID_COL_NAME + "=?", new String[] { Long.toString(labelId) }, null, null, null); try { if (c.moveToNext()) { return c.getString(0); } } finally { c.close(); } } return ""; } public DatabaseHelperBasic getDbHelper() { if (dbHelper == null) { dbHelper = new DatabaseHelperBasic(LabelShortcut.this); } return dbHelper; } private void reloadData() { final String title = retrieveTitle(); Cursor prevCursor = null; if (cursorAdapter != null) { prevCursor = cursorAdapter.getCursor(); } final Cursor actualCursor = reloadGrid(); updateTitleView(title); if (cursorAdapter == null) { createAdapter(actualCursor); } else { cursorAdapter.changeCursor(actualCursor); } if (prevCursor != null && !prevCursor.isClosed()) { prevCursor.close(); } if (!firstTime) { setVisible(true); } else { firstTime = false; } } private void reloadDataExternalThread() { Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() { public boolean queueIdle() { final String title = retrieveTitle(); final Cursor prevCursor; if (cursorAdapter != null) { prevCursor = cursorAdapter.getCursor(); } else { prevCursor = null; } final Cursor actualCursor = reloadGrid(); updateTitleView(title); if (cursorAdapter == null) { createAdapter(actualCursor); } else { cursorAdapter.changeCursor(actualCursor); } if (prevCursor != null && !prevCursor.isClosed()) { prevCursor.close(); } if (!firstTime) { setVisible(true); } else { firstTime = false; } return false; } }); } private void createAdapter(Cursor cursor) { DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); final float density = dm.density; final int iconSize = (int) (48 * density); final int width = (int) (65 * density); final int height = (int) (78 * density); final AbsListView.LayoutParams layoutParams = new AbsListView.LayoutParams(width, height); cursorAdapter = new SimpleCursorAdapter(this, 0, cursor, new String[] { LabelDao.ID_COL_NAME }, new int[] { R.id.name }) { @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { TextView t = new TextView(context); t.setLayoutParams(layoutParams); t.setGravity(Gravity.CENTER_HORIZONTAL); t.setTextSize(12); return t; } @Override public void bindView(View view, Context context, Cursor cursor) { TextView v = (TextView) view; v.setText(cursor.getString(1)); Drawable b = null; if (cursor.getColumnCount() == 4) { if (!cursor.isNull(3)) { byte[] imageBytes = cursor.getBlob(3); b = new BitmapDrawable(BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length)); } else { if (!cursor.isNull(2)) { int ic = Label.convertToIcon(cursor.getInt(2)); if (ic > 0) { b = context.getResources().getDrawable(ic); } } } } else { byte[] imageBytes = cursor.getBlob(2); if (imageBytes != null) { Bitmap bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length); if (bitmap != null) { b = new BitmapDrawable(bitmap); } } } if (b == null) { b = context.getResources().getDrawable(R.drawable.icon_default); } b.setBounds(0, 0, iconSize, iconSize); v.setCompoundDrawables(null, b, null, null); } }; grid.setAdapter(cursorAdapter); } private SimpleCursorAdapter cursorAdapter; private void createGrid() { setContentView(R.layout.shortcut_grid); grid = (GridView) findViewById(R.id.shortcutGrid); grid.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long arg3) { Cursor item = (Cursor) cursorAdapter.getItem(pos); if (labelId == ALL_LABELS_ID) { labelId = item.getLong(0); reloadData(); } else { Intent i = new Intent(Intent.ACTION_MAIN); i.addCategory(Intent.CATEGORY_LAUNCHER); i.setClassName(item.getString(3), item.getString(4)); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivity(i); if (prefs.getBoolean("close_folder_after_launch", false)) { finish(); } } catch (ActivityNotFoundException e) { Toast.makeText(LabelShortcut.this, R.string.error_while_launching_activity, Toast.LENGTH_SHORT).show(); } } } }); grid.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; AbstractCursor c = (AbstractCursor) grid.getAdapter().getItem(info.position); if (c.getColumnCount() != 4) { ApplicationContextMenuManager.createMenu(LabelShortcut.this, menu, c.getString(1), c.getInt(0)); } } }); if (!firstTime) { setVisible(false); } } @Override public boolean onContextItemSelected(MenuItem item) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); if (grid != null) { AbstractCursor c = (AbstractCursor) grid.getAdapter().getItem(info.position); ApplicationContextMenuManager.onContextItemSelected(item, c.getString(3), c.getString(4), this, chooseLabelDialog); return true; } return false; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (ApplicationContextMenuManager.onActivityResult(this, requestCode, resultCode, data)) { requeryCursor(); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (onBack()) { return true; } } return super.onKeyDown(keyCode, event); } private boolean onBack() { if (allLabelsSelected) { if (labelId != ALL_LABELS_ID) { labelId = ALL_LABELS_ID; reloadData(); return true; } } return false; } @Override public boolean onCreateOptionsMenu(Menu menu) { return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { if (labelId != ALL_LABELS_ID && labelId != ALL_STARRED_ID && labelId != OTHER_APPS) { showChooseAppsDialog(); } return false; } private void showChooseAppsDialog() { chooseAppsDialogCreator.setCurrentLabelId(labelId); showDialog(chooseAppsDialogCreator); } private void updateTitleView(String title) { if (titleView == null) { RelativeLayout titleLayout = (RelativeLayout) findViewById(R.id.titleLayout); titleView = (TextView) titleLayout.findViewById(R.id.title); starCheck = (CheckBox) titleLayout.findViewById(R.id.starCheck); starCheck.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { Editor edit = prefs.edit(); edit.putBoolean(ONLY_STARRED_PREF, isChecked); edit.commit(); reloadData(); } }); starCheck.setChecked(prefs.getBoolean(ONLY_STARRED_PREF, false)); boolean showCloseButton = prefs.getBoolean("show_close_button_in_folder", true); View closeButton = titleLayout.findViewById(R.id.closeButton); closeButton.setVisibility(showCloseButton ? View.VISIBLE : View.INVISIBLE); if (showCloseButton) { closeButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { finish(); } }); } } titleView.setText(title); int v = labelId > 0 ? View.VISIBLE : View.INVISIBLE; if (starCheck.getVisibility() != v) { starCheck.setVisibility(v); } } private void requeryCursor() { SimpleCursorAdapter adapter = (SimpleCursorAdapter) grid.getAdapter(); if (adapter != null) { Cursor c = adapter.getCursor(); if (c != null) { c.requery(); } } } private boolean inViewBounds(View view, int x, int y, int fuzz) { Rect rect = new Rect(); int[] loc = new int[2]; view.getDrawingRect(rect); view.getLocationOnScreen(loc); rect.offset(loc[0], loc[1]); rect.inset(-fuzz, -fuzz); return rect.contains(x, y); } @Override public boolean onTouchEvent(MotionEvent event) { boolean ret = super.onTouchEvent(event); if (!ret) { if (!inViewBounds(getWindow().getDecorView(), (int)event.getRawX(), (int)event.getRawY(), 20)) finish(); return true; } return ret; } }