Home | History | Annotate | Download | only in widgetpreview
      1 /*
      2  * Copyright (C) 2010 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 
     17 package com.android.widgetpreview;
     18 
     19 import android.app.Activity;
     20 import android.appwidget.AppWidgetHost;
     21 import android.appwidget.AppWidgetHostView;
     22 import android.appwidget.AppWidgetManager;
     23 import android.appwidget.AppWidgetProviderInfo;
     24 import android.content.ActivityNotFoundException;
     25 import android.content.Intent;
     26 import android.content.res.Configuration;
     27 import android.content.res.Resources;
     28 import android.graphics.Bitmap;
     29 import android.graphics.Bitmap.CompressFormat;
     30 import android.graphics.Bitmap.Config;
     31 import android.graphics.Canvas;
     32 import android.net.Uri;
     33 import android.os.Bundle;
     34 import android.os.Environment;
     35 import android.util.Log;
     36 import android.view.View;
     37 import android.view.View.OnClickListener;
     38 import android.view.ViewGroup;
     39 import android.widget.Button;
     40 import android.widget.FrameLayout;
     41 import android.widget.Toast;
     42 
     43 import java.io.File;
     44 import java.io.FileOutputStream;
     45 import java.io.IOException;
     46 
     47 public class WidgetPreviewActivity extends Activity implements OnClickListener {
     48 
     49     private static final String LOG_TAG = "WidgetPreviewActivity";
     50     private static final boolean DEBUG = true;
     51     private static final int APPWIDGET_HOST_ID = 2048;
     52     private static final int REQUEST_WIDGET = 0;
     53     private static final int REQUEST_CONFIGURE = 1;
     54 
     55     private AppWidgetHost mAppWidgetHost = null;
     56     private FrameLayout mAppWidgetFrame = null;
     57     private AppWidgetHostView mAppWidgetView = null;
     58     private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
     59     private String mAppWidgetName;
     60     private int mPreviewWidth;
     61     private int mPreviewHeight;
     62 
     63     private Button mSnapshotButton = null;
     64     private Button mEmailButton = null;
     65 
     66     @Override
     67     public void onCreate(Bundle savedInstanceState) {
     68         super.onCreate(savedInstanceState);
     69         setContentView(R.layout.activity_main);
     70         mAppWidgetFrame = (FrameLayout)findViewById(R.id.main_frame);
     71         mSnapshotButton = (Button)findViewById(R.id.snapshot_button);
     72         mSnapshotButton.setOnClickListener(this);
     73         mEmailButton = (Button)findViewById(R.id.email_button);
     74         mEmailButton.setOnClickListener(this);
     75 
     76         mAppWidgetHost = new AppWidgetHost(getApplicationContext(), APPWIDGET_HOST_ID);
     77 
     78         final Object retainedObj = getLastNonConfigurationInstance();
     79         if (retainedObj instanceof AppWidgetProviderInfo) {
     80             AppWidgetProviderInfo info = (AppWidgetProviderInfo) retainedObj;
     81             int id = mAppWidgetHost.allocateAppWidgetId();
     82             AppWidgetManager.getInstance(getBaseContext()).bindAppWidgetIdIfAllowed(id, info.provider);
     83             setAppWidget(id);
     84         } else {
     85             startChooseActivity();
     86         }
     87     }
     88 
     89     @Override
     90     public void onStart() {
     91         super.onStart();
     92         mAppWidgetHost.startListening();
     93     }
     94 
     95     @Override
     96     public Object onRetainNonConfigurationInstance() {
     97         AppWidgetProviderInfo info = AppWidgetManager.getInstance(
     98                 getBaseContext()).getAppWidgetInfo(mAppWidgetId);
     99         return info;
    100     }
    101 
    102     private void startChooseActivity() {
    103         int id = mAppWidgetHost.allocateAppWidgetId();
    104         Intent selectIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
    105         selectIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id);
    106         startActivityForResult(selectIntent, REQUEST_WIDGET);
    107     }
    108 
    109     @Override
    110     public void onActivityResult(int requestCode, int resultCode, Intent data) {
    111         if (requestCode == REQUEST_WIDGET) {
    112             if (data != null) {
    113                 int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
    114                 if (data.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) {
    115                     appWidgetId = data.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
    116                 }
    117 
    118                 if (resultCode == RESULT_OK) {
    119                     setAppWidget(appWidgetId);
    120                 } else {
    121                     mAppWidgetHost.deleteAppWidgetId(appWidgetId);
    122                     finish();
    123                 }
    124             } else {
    125                 finish();
    126             }
    127         } else if (requestCode == REQUEST_CONFIGURE) {
    128             if (data != null) {
    129                 int appWidgetId = data.getExtras().getInt(
    130                         AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
    131                 if (resultCode == RESULT_OK) {
    132                     finishSetAppWidget(appWidgetId);
    133                 } else {
    134                     mAppWidgetHost.deleteAppWidgetId(appWidgetId);
    135                 }
    136             }
    137         }
    138     }
    139 
    140     private void setAppWidget(int appWidgetId) {
    141         if (mAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
    142             mAppWidgetHost.deleteAppWidgetId(mAppWidgetId);
    143         }
    144 
    145         /* Check for configuration */
    146         AppWidgetProviderInfo providerInfo =
    147             AppWidgetManager.getInstance(getBaseContext()).getAppWidgetInfo(appWidgetId);
    148 
    149         if (providerInfo.configure != null) {
    150             Intent configureIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
    151             configureIntent.setComponent(providerInfo.configure);
    152             configureIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    153 
    154             if (configureIntent != null) {
    155                 try {
    156                     startActivityForResult(configureIntent, REQUEST_CONFIGURE);
    157                 } catch (ActivityNotFoundException e) {
    158                     Log.d(LOG_TAG, "Configuration activity not found: " + e);
    159                     Toast errorToast = Toast.makeText(
    160                             getBaseContext(), R.string.configure_error, Toast.LENGTH_SHORT);
    161                     errorToast.show();
    162                 }
    163             }
    164         } else {
    165             finishSetAppWidget(appWidgetId);
    166         }
    167     }
    168 
    169     private void finishSetAppWidget(int appWidgetId) {
    170         AppWidgetProviderInfo providerInfo =
    171             AppWidgetManager.getInstance(getBaseContext()).getAppWidgetInfo(appWidgetId);
    172         if (providerInfo != null) {
    173             mAppWidgetView =
    174                     mAppWidgetHost.createView(getBaseContext(), appWidgetId, providerInfo);
    175 
    176             int [] dimensions =
    177                     getLauncherCellDimensions(providerInfo.minWidth, providerInfo.minHeight);
    178 
    179             mPreviewWidth = dimensions[0];
    180             mPreviewHeight = dimensions[1];
    181 
    182             mAppWidgetName =
    183                 AppWidgetManager.getInstance(getBaseContext()).getAppWidgetInfo(appWidgetId).label;
    184             mAppWidgetName = mAppWidgetName.replaceAll("[^a-zA-Z0-9]", "_");
    185 
    186             ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(
    187                     ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    188             mAppWidgetView.setLayoutParams(p);
    189             mAppWidgetFrame.removeAllViews();
    190             mAppWidgetHost.deleteAppWidgetId(mAppWidgetId);
    191             mAppWidgetFrame.addView(mAppWidgetView, mPreviewWidth, mPreviewHeight);
    192             mAppWidgetId = appWidgetId;
    193         }
    194     }
    195 
    196     // Taken from CellLayout.java
    197     public int[] getLauncherCellDimensions(int width, int height) {
    198         // Always assume we're working with the smallest span to make sure we
    199         // reserve enough space in both orientations.
    200         Resources resources = getResources();
    201         int cellWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width);
    202         int cellHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height);
    203         int widthGap = resources.getDimensionPixelSize(R.dimen.workspace_width_gap);
    204         int heightGap = resources.getDimensionPixelSize(R.dimen.workspace_height_gap);
    205         int previewCellSize = resources.getDimensionPixelSize(R.dimen.preview_cell_size);
    206 
    207         // This logic imitates Launcher's CellLayout.rectToCell.
    208         // Always round up to next largest cell
    209         int smallerSize = Math.min(cellWidth, cellHeight);
    210         int spanX = (width + smallerSize) / smallerSize;
    211         int spanY = (height + smallerSize) / smallerSize;
    212 
    213         // We use a fixed preview cell size so that you get the same preview image for
    214         // the same cell-sized widgets across all devices
    215         width = spanX * previewCellSize + ((spanX - 1) * widthGap);
    216         height = spanY * previewCellSize + ((spanY - 1) * heightGap);
    217         return new int[] { width, height };
    218     }
    219 
    220     private File buildFile(String name) {
    221         if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
    222             return null;
    223         }
    224 
    225         File path = Environment.getExternalStoragePublicDirectory(
    226                 Environment.DIRECTORY_DOWNLOADS);
    227         int orientationCode = getResources().getConfiguration().orientation;
    228         String orientation;
    229         if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
    230             orientation = "landscape";
    231         } else if (orientationCode == Configuration.ORIENTATION_PORTRAIT) {
    232             orientation = "portrait";
    233         } else if (orientationCode == Configuration.ORIENTATION_SQUARE) {
    234             orientation = "square";
    235         } else {
    236             orientation = "undefined";
    237         }
    238         return new File(path, name + "_ori_" + orientation + ".png");
    239     }
    240 
    241     public Bitmap getPreviewBitmap() {
    242         mAppWidgetView.invalidate();
    243         Bitmap bmp = Bitmap.createBitmap(
    244                 mAppWidgetView.getWidth(), mAppWidgetView.getHeight(), Config.ARGB_8888);
    245         Canvas c = new Canvas(bmp);
    246         mAppWidgetView.draw(c);
    247         return bmp;
    248     }
    249 
    250     private boolean saveImage(Bitmap bmp, String name) {
    251         File pic = buildFile(mAppWidgetName);
    252         if (pic == null) {
    253             Log.d(LOG_TAG, "External storage not present");
    254             return false;
    255         }
    256 
    257         pic.getParentFile().mkdirs();
    258         FileOutputStream fout = null;
    259         try {
    260             fout = new FileOutputStream(pic);
    261             if (!bmp.compress(CompressFormat.PNG, 100, fout)) {
    262                 Log.d(LOG_TAG, "Failed to compress image");
    263                 return false;
    264             }
    265             return true;
    266         } catch (IOException e) {
    267             Log.d(LOG_TAG, "Error writing to disk: " + e);
    268         } finally {
    269             try {
    270                 if (fout != null) {
    271                     fout.close();
    272                 }
    273             } catch (IOException e) {
    274                 Log.d(LOG_TAG, "Could not close file: " + e);
    275             }
    276         }
    277         return false;
    278     }
    279 
    280     @Override
    281     public void onBackPressed() {
    282         if (!getFragmentManager().popBackStackImmediate()) {
    283             startChooseActivity();
    284         }
    285     }
    286 
    287     @Override
    288     public void onClick(View v) {
    289         if (v == mSnapshotButton) {
    290             int textId = R.string.saving_preview;
    291 
    292             Toast preToast = Toast.makeText(getBaseContext(), textId, Toast.LENGTH_SHORT);
    293             preToast.show();
    294 
    295             Bitmap bmp = getPreviewBitmap();
    296             if (saveImage(bmp, mAppWidgetName)) {
    297                 textId = R.string.preview_saved;
    298             } else {
    299                 textId = R.string.preview_save_error;
    300             }
    301 
    302             Toast postToast = Toast.makeText(getBaseContext(), textId, Toast.LENGTH_SHORT);
    303             postToast.show();
    304         } else if (v == mEmailButton) {
    305             File file = buildFile(mAppWidgetName);
    306             if (file.exists()) {
    307                 Intent emailIntent = new Intent(Intent.ACTION_SEND);
    308                 emailIntent.setType("image/png");
    309                 emailIntent.putExtra(Intent.EXTRA_SUBJECT,
    310                         getResources().getString(R.string.email_subject));
    311                 emailIntent.putExtra(Intent.EXTRA_TEXT,
    312                         getResources().getString(R.string.email_body));
    313                 emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
    314                 startActivity(emailIntent);
    315             } else {
    316                 Toast postToast = Toast.makeText(
    317                         getBaseContext(), R.string.no_preview, Toast.LENGTH_SHORT);
    318                 postToast.show();
    319             }
    320         }
    321     }
    322 }
    323