BrowserSnapshotPage.java revision 2bc8042224be51966d748b870768ec1b376a1621
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.browser; 17 18import android.app.Fragment; 19import android.app.LoaderManager.LoaderCallbacks; 20import android.content.ContentResolver; 21import android.content.ContentUris; 22import android.content.Context; 23import android.content.CursorLoader; 24import android.content.Loader; 25import android.database.Cursor; 26import android.graphics.Bitmap; 27import android.graphics.BitmapFactory; 28import android.net.Uri; 29import android.os.Bundle; 30import android.view.ContextMenu; 31import android.view.ContextMenu.ContextMenuInfo; 32import android.view.LayoutInflater; 33import android.view.MenuInflater; 34import android.view.MenuItem; 35import android.view.View; 36import android.view.View.MeasureSpec; 37import android.view.ViewGroup; 38import android.widget.AdapterView; 39import android.widget.AdapterView.AdapterContextMenuInfo; 40import android.widget.AdapterView.OnItemClickListener; 41import android.widget.GridView; 42import android.widget.ImageView; 43import android.widget.ResourceCursorAdapter; 44import android.widget.TextView; 45 46import com.android.browser.provider.BrowserProvider2.Snapshots; 47 48import java.text.DateFormat; 49import java.util.Date; 50 51public class BrowserSnapshotPage extends Fragment implements 52 LoaderCallbacks<Cursor>, OnItemClickListener { 53 54 public static final String EXTRA_ANIMATE_ID = "animate_id"; 55 56 private static final int LOADER_SNAPSHOTS = 1; 57 private static final String[] PROJECTION = new String[] { 58 Snapshots._ID, 59 Snapshots.TITLE, 60 "length(" + Snapshots.VIEWSTATE + ")", 61 Snapshots.THUMBNAIL, 62 Snapshots.FAVICON, 63 Snapshots.URL, 64 }; 65 private static final int SNAPSHOT_TITLE = 1; 66 private static final int SNAPSHOT_VIEWSTATE_LENGTH = 2; 67 private static final int SNAPSHOT_THUMBNAIL = 3; 68 private static final int SNAPSHOT_FAVICON = 4; 69 private static final int SNAPSHOT_URL = 5; 70 71 GridView mGrid; 72 View mEmpty; 73 SnapshotAdapter mAdapter; 74 UiController mUiController; 75 76 public static BrowserSnapshotPage newInstance(UiController uiController, 77 Bundle extras) { 78 BrowserSnapshotPage instance = new BrowserSnapshotPage(); 79 instance.mUiController = uiController; 80 instance.setArguments(extras); 81 return instance; 82 } 83 84 @Override 85 public View onCreateView(LayoutInflater inflater, ViewGroup container, 86 Bundle savedInstanceState) { 87 View view = inflater.inflate(R.layout.snapshots, container, false); 88 mEmpty = view.findViewById(android.R.id.empty); 89 mGrid = (GridView) view.findViewById(R.id.grid); 90 setupGrid(inflater); 91 getLoaderManager().initLoader(LOADER_SNAPSHOTS, null, this); 92 return view; 93 } 94 95 @Override 96 public void onDestroyView() { 97 super.onDestroyView(); 98 getLoaderManager().destroyLoader(LOADER_SNAPSHOTS); 99 mAdapter.changeCursor(null); 100 mAdapter = null; 101 } 102 103 void setupGrid(LayoutInflater inflater) { 104 View item = inflater.inflate(R.layout.snapshot_item, mGrid, false); 105 int mspec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 106 item.measure(mspec, mspec); 107 int width = item.getMeasuredWidth(); 108 mGrid.setColumnWidth(width); 109 mGrid.setOnItemClickListener(this); 110 mGrid.setOnCreateContextMenuListener(this); 111 } 112 113 @Override 114 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 115 if (id == LOADER_SNAPSHOTS) { 116 // TODO: Sort by date created 117 return new CursorLoader(getActivity(), 118 Snapshots.CONTENT_URI, PROJECTION, 119 null, null, null); 120 } 121 return null; 122 } 123 124 @Override 125 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 126 if (loader.getId() == LOADER_SNAPSHOTS) { 127 if (mAdapter == null) { 128 mAdapter = new SnapshotAdapter(getActivity(), data); 129 mGrid.setAdapter(mAdapter); 130 } else { 131 mAdapter.changeCursor(data); 132 } 133 boolean empty = mAdapter.isEmpty(); 134 mGrid.setVisibility(empty ? View.GONE : View.VISIBLE); 135 mEmpty.setVisibility(empty ? View.VISIBLE : View.GONE); 136 } 137 } 138 139 @Override 140 public void onLoaderReset(Loader<Cursor> loader) { 141 } 142 143 @Override 144 public void onCreateContextMenu(ContextMenu menu, View v, 145 ContextMenuInfo menuInfo) { 146 MenuInflater inflater = getActivity().getMenuInflater(); 147 inflater.inflate(R.menu.snapshots_context, menu); 148 // Create the header, re-use BookmarkItem (has the layout we want) 149 BookmarkItem header = new BookmarkItem(getActivity()); 150 AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; 151 populateBookmarkItem(mAdapter.getItem(info.position), header); 152 menu.setHeaderView(header); 153 } 154 155 private void populateBookmarkItem(Cursor cursor, BookmarkItem item) { 156 item.setName(cursor.getString(SNAPSHOT_TITLE)); 157 item.setUrl(cursor.getString(SNAPSHOT_URL)); 158 item.setFavicon(getBitmap(cursor, SNAPSHOT_FAVICON)); 159 } 160 161 static Bitmap getBitmap(Cursor cursor, int columnIndex) { 162 byte[] data = cursor.getBlob(columnIndex); 163 if (data == null) { 164 return null; 165 } 166 return BitmapFactory.decodeByteArray(data, 0, data.length); 167 } 168 169 @Override 170 public boolean onContextItemSelected(MenuItem item) { 171 if (item.getItemId() == R.id.delete_context_menu_id) { 172 AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); 173 deleteSnapshot(info.id); 174 return true; 175 } 176 return super.onContextItemSelected(item); 177 } 178 179 void deleteSnapshot(long id) { 180 final Uri uri = ContentUris.withAppendedId(Snapshots.CONTENT_URI, id); 181 final ContentResolver cr = getActivity().getContentResolver(); 182 new Thread() { 183 @Override 184 public void run() { 185 cr.delete(uri, null, null); 186 } 187 }.start(); 188 189 } 190 191 @Override 192 public void onItemClick(AdapterView<?> parent, View view, int position, 193 long id) { 194 mUiController.removeComboView(); 195 mUiController.createNewSnapshotTab(id, true); 196 } 197 198 private static class SnapshotAdapter extends ResourceCursorAdapter { 199 200 public SnapshotAdapter(Context context, Cursor c) { 201 super(context, R.layout.snapshot_item, c, 0); 202 } 203 204 @Override 205 public void bindView(View view, Context context, Cursor cursor) { 206 ImageView thumbnail = (ImageView) view.findViewById(R.id.thumb); 207 byte[] thumbBlob = cursor.getBlob(SNAPSHOT_THUMBNAIL); 208 if (thumbBlob == null) { 209 thumbnail.setImageResource(R.drawable.browser_thumbnail); 210 } else { 211 Bitmap thumbBitmap = BitmapFactory.decodeByteArray( 212 thumbBlob, 0, thumbBlob.length); 213 thumbnail.setImageBitmap(thumbBitmap); 214 } 215 TextView title = (TextView) view.findViewById(R.id.title); 216 title.setText(cursor.getString(SNAPSHOT_TITLE)); 217 TextView size = (TextView) view.findViewById(R.id.size); 218 int stateLen = cursor.getInt(SNAPSHOT_VIEWSTATE_LENGTH); 219 size.setText(String.format("%.1fMB", stateLen / 1024f / 1024f)); 220 // We don't actually have the date in the database yet 221 // Use the current date as a placeholder 222 TextView date = (TextView) view.findViewById(R.id.date); 223 DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT); 224 date.setText(dateFormat.format(new Date())); 225 } 226 227 @Override 228 public Cursor getItem(int position) { 229 return (Cursor) super.getItem(position); 230 } 231 } 232 233} 234