Home | History | Annotate | Download | only in browser
      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  */
     16 package com.android.browser;
     17 
     18 import android.animation.Animator;
     19 import android.animation.Animator.AnimatorListener;
     20 import android.animation.AnimatorSet;
     21 import android.animation.ObjectAnimator;
     22 import android.app.Fragment;
     23 import android.app.LoaderManager.LoaderCallbacks;
     24 import android.content.ContentResolver;
     25 import android.content.ContentUris;
     26 import android.content.Context;
     27 import android.content.CursorLoader;
     28 import android.content.Loader;
     29 import android.database.Cursor;
     30 import android.graphics.Bitmap;
     31 import android.graphics.BitmapFactory;
     32 import android.net.Uri;
     33 import android.os.Bundle;
     34 import android.view.ContextMenu;
     35 import android.view.ContextMenu.ContextMenuInfo;
     36 import android.view.LayoutInflater;
     37 import android.view.MenuInflater;
     38 import android.view.MenuItem;
     39 import android.view.View;
     40 import android.view.View.MeasureSpec;
     41 import android.view.ViewGroup;
     42 import android.widget.AdapterView;
     43 import android.widget.AdapterView.AdapterContextMenuInfo;
     44 import android.widget.AdapterView.OnItemClickListener;
     45 import android.widget.GridView;
     46 import android.widget.ImageView;
     47 import android.widget.ResourceCursorAdapter;
     48 import android.widget.TextView;
     49 
     50 import com.android.browser.provider.SnapshotProvider.Snapshots;
     51 
     52 import java.text.DateFormat;
     53 import java.util.Date;
     54 
     55 public class BrowserSnapshotPage extends Fragment implements
     56         LoaderCallbacks<Cursor>, OnItemClickListener {
     57 
     58     public static final String EXTRA_ANIMATE_ID = "animate_id";
     59 
     60     private static final int LOADER_SNAPSHOTS = 1;
     61     private static final String[] PROJECTION = new String[] {
     62         Snapshots._ID,
     63         Snapshots.TITLE,
     64         Snapshots.VIEWSTATE_SIZE,
     65         Snapshots.THUMBNAIL,
     66         Snapshots.FAVICON,
     67         Snapshots.URL,
     68         Snapshots.DATE_CREATED,
     69     };
     70     private static final int SNAPSHOT_ID = 0;
     71     private static final int SNAPSHOT_TITLE = 1;
     72     private static final int SNAPSHOT_VIEWSTATE_SIZE = 2;
     73     private static final int SNAPSHOT_THUMBNAIL = 3;
     74     private static final int SNAPSHOT_FAVICON = 4;
     75     private static final int SNAPSHOT_URL = 5;
     76     private static final int SNAPSHOT_DATE_CREATED = 6;
     77 
     78     GridView mGrid;
     79     View mEmpty;
     80     SnapshotAdapter mAdapter;
     81     CombinedBookmarksCallbacks mCallback;
     82     long mAnimateId;
     83 
     84     @Override
     85     public void onCreate(Bundle savedInstanceState) {
     86         super.onCreate(savedInstanceState);
     87         mCallback = (CombinedBookmarksCallbacks) getActivity();
     88         mAnimateId = getArguments().getLong(EXTRA_ANIMATE_ID);
     89     }
     90 
     91     @Override
     92     public View onCreateView(LayoutInflater inflater, ViewGroup container,
     93             Bundle savedInstanceState) {
     94         View view = inflater.inflate(R.layout.snapshots, container, false);
     95         mEmpty = view.findViewById(android.R.id.empty);
     96         mGrid = (GridView) view.findViewById(R.id.grid);
     97         setupGrid(inflater);
     98         getLoaderManager().initLoader(LOADER_SNAPSHOTS, null, this);
     99         return view;
    100     }
    101 
    102     @Override
    103     public void onDestroyView() {
    104         super.onDestroyView();
    105         getLoaderManager().destroyLoader(LOADER_SNAPSHOTS);
    106         if (mAdapter != null) {
    107             mAdapter.changeCursor(null);
    108             mAdapter = null;
    109         }
    110     }
    111 
    112     void setupGrid(LayoutInflater inflater) {
    113         View item = inflater.inflate(R.layout.snapshot_item, mGrid, false);
    114         int mspec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
    115         item.measure(mspec, mspec);
    116         int width = item.getMeasuredWidth();
    117         mGrid.setColumnWidth(width);
    118         mGrid.setOnItemClickListener(this);
    119         mGrid.setOnCreateContextMenuListener(this);
    120     }
    121 
    122     @Override
    123     public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    124         if (id == LOADER_SNAPSHOTS) {
    125             return new CursorLoader(getActivity(),
    126                     Snapshots.CONTENT_URI, PROJECTION,
    127                     null, null, Snapshots.DATE_CREATED + " DESC");
    128         }
    129         return null;
    130     }
    131 
    132     @Override
    133     public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    134         if (loader.getId() == LOADER_SNAPSHOTS) {
    135             if (mAdapter == null) {
    136                 mAdapter = new SnapshotAdapter(getActivity(), data);
    137                 mGrid.setAdapter(mAdapter);
    138             } else {
    139                 mAdapter.changeCursor(data);
    140             }
    141             if (mAnimateId > 0) {
    142                 mAdapter.animateIn(mAnimateId);
    143                 mAnimateId = 0;
    144                 getArguments().remove(EXTRA_ANIMATE_ID);
    145             }
    146             boolean empty = mAdapter.isEmpty();
    147             mGrid.setVisibility(empty ? View.GONE : View.VISIBLE);
    148             mEmpty.setVisibility(empty ? View.VISIBLE : View.GONE);
    149         }
    150     }
    151 
    152     @Override
    153     public void onLoaderReset(Loader<Cursor> loader) {
    154     }
    155 
    156     @Override
    157     public void onCreateContextMenu(ContextMenu menu, View v,
    158             ContextMenuInfo menuInfo) {
    159         MenuInflater inflater = getActivity().getMenuInflater();
    160         inflater.inflate(R.menu.snapshots_context, menu);
    161         // Create the header, re-use BookmarkItem (has the layout we want)
    162         BookmarkItem header = new BookmarkItem(getActivity());
    163         header.setEnableScrolling(true);
    164         AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
    165         populateBookmarkItem(mAdapter.getItem(info.position), header);
    166         menu.setHeaderView(header);
    167     }
    168 
    169     private void populateBookmarkItem(Cursor cursor, BookmarkItem item) {
    170         item.setName(cursor.getString(SNAPSHOT_TITLE));
    171         item.setUrl(cursor.getString(SNAPSHOT_URL));
    172         item.setFavicon(getBitmap(cursor, SNAPSHOT_FAVICON));
    173     }
    174 
    175     static Bitmap getBitmap(Cursor cursor, int columnIndex) {
    176         byte[] data = cursor.getBlob(columnIndex);
    177         if (data == null) {
    178             return null;
    179         }
    180         return BitmapFactory.decodeByteArray(data, 0, data.length);
    181     }
    182 
    183     @Override
    184     public boolean onContextItemSelected(MenuItem item) {
    185         if (item.getItemId() == R.id.delete_context_menu_id) {
    186             AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
    187             deleteSnapshot(info.id);
    188             return true;
    189         }
    190         return super.onContextItemSelected(item);
    191     }
    192 
    193     void deleteSnapshot(long id) {
    194         final Uri uri = ContentUris.withAppendedId(Snapshots.CONTENT_URI, id);
    195         final ContentResolver cr = getActivity().getContentResolver();
    196         new Thread() {
    197             @Override
    198             public void run() {
    199                 cr.delete(uri, null, null);
    200             }
    201         }.start();
    202 
    203     }
    204 
    205     @Override
    206     public void onItemClick(AdapterView<?> parent, View view, int position,
    207             long id) {
    208         mCallback.openSnapshot(id);
    209     }
    210 
    211     private static class SnapshotAdapter extends ResourceCursorAdapter {
    212         private long mAnimateId;
    213         private AnimatorSet mAnimation;
    214         private View mAnimationTarget;
    215 
    216         public SnapshotAdapter(Context context, Cursor c) {
    217             super(context, R.layout.snapshot_item, c, 0);
    218             mAnimation = new AnimatorSet();
    219             mAnimation.playTogether(
    220                     ObjectAnimator.ofFloat(null, View.SCALE_X, 0f, 1f),
    221                     ObjectAnimator.ofFloat(null, View.SCALE_Y, 0f, 1f));
    222             mAnimation.setStartDelay(100);
    223             mAnimation.setDuration(400);
    224             mAnimation.addListener(new AnimatorListener() {
    225 
    226                 @Override
    227                 public void onAnimationStart(Animator animation) {
    228                 }
    229 
    230                 @Override
    231                 public void onAnimationRepeat(Animator animation) {
    232                 }
    233 
    234                 @Override
    235                 public void onAnimationEnd(Animator animation) {
    236                     mAnimateId = 0;
    237                     mAnimationTarget = null;
    238                 }
    239 
    240                 @Override
    241                 public void onAnimationCancel(Animator animation) {
    242                 }
    243             });
    244         }
    245 
    246         public void animateIn(long id) {
    247             mAnimateId = id;
    248         }
    249 
    250         @Override
    251         public void bindView(View view, Context context, Cursor cursor) {
    252             long id = cursor.getLong(SNAPSHOT_ID);
    253             if (id == mAnimateId) {
    254                 if (mAnimationTarget != view) {
    255                     float scale = 0f;
    256                     if (mAnimationTarget != null) {
    257                         scale = mAnimationTarget.getScaleX();
    258                         mAnimationTarget.setScaleX(1f);
    259                         mAnimationTarget.setScaleY(1f);
    260                     }
    261                     view.setScaleX(scale);
    262                     view.setScaleY(scale);
    263                 }
    264                 mAnimation.setTarget(view);
    265                 mAnimationTarget = view;
    266                 if (!mAnimation.isRunning()) {
    267                     mAnimation.start();
    268                 }
    269 
    270             }
    271             ImageView thumbnail = (ImageView) view.findViewById(R.id.thumb);
    272             byte[] thumbBlob = cursor.getBlob(SNAPSHOT_THUMBNAIL);
    273             if (thumbBlob == null) {
    274                 thumbnail.setImageResource(R.drawable.browser_thumbnail);
    275             } else {
    276                 Bitmap thumbBitmap = BitmapFactory.decodeByteArray(
    277                         thumbBlob, 0, thumbBlob.length);
    278                 thumbnail.setImageBitmap(thumbBitmap);
    279             }
    280             TextView title = (TextView) view.findViewById(R.id.title);
    281             title.setText(cursor.getString(SNAPSHOT_TITLE));
    282             TextView size = (TextView) view.findViewById(R.id.size);
    283             if (size != null) {
    284                 int stateLen = cursor.getInt(SNAPSHOT_VIEWSTATE_SIZE);
    285                 size.setText(String.format("%.2fMB", stateLen / 1024f / 1024f));
    286             }
    287             long timestamp = cursor.getLong(SNAPSHOT_DATE_CREATED);
    288             TextView date = (TextView) view.findViewById(R.id.date);
    289             DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT);
    290             date.setText(dateFormat.format(new Date(timestamp)));
    291         }
    292 
    293         @Override
    294         public Cursor getItem(int position) {
    295             return (Cursor) super.getItem(position);
    296         }
    297     }
    298 
    299 }
    300