DialogDetailsView.java revision a29127be09f74782dee7d6c18cf6dd50728652aa
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 17package com.android.gallery3d.ui; 18 19import static com.android.gallery3d.ui.DetailsWindowConfig.FONT_SIZE; 20import static com.android.gallery3d.ui.DetailsWindowConfig.LEFT_RIGHT_EXTRA_PADDING; 21import static com.android.gallery3d.ui.DetailsWindowConfig.LINE_SPACING; 22import static com.android.gallery3d.ui.DetailsWindowConfig.PREFERRED_WIDTH; 23import static com.android.gallery3d.ui.DetailsWindowConfig.TOP_BOTTOM_EXTRA_PADDING; 24 25import com.android.gallery3d.R; 26import com.android.gallery3d.app.GalleryActivity; 27import com.android.gallery3d.common.Utils; 28import com.android.gallery3d.data.MediaDetails; 29import com.android.gallery3d.ui.DetailsAddressResolver.AddressResolvingListener; 30import com.android.gallery3d.ui.DetailsHelper.CloseListener; 31import com.android.gallery3d.ui.DetailsHelper.DetailsViewContainer; 32import com.android.gallery3d.ui.DetailsHelper.DetailsSource; 33import com.android.gallery3d.util.Future; 34import com.android.gallery3d.util.FutureListener; 35import com.android.gallery3d.util.GalleryUtils; 36import com.android.gallery3d.util.ReverseGeocoder; 37import com.android.gallery3d.util.ThreadPool.Job; 38import com.android.gallery3d.util.ThreadPool.JobContext; 39 40import android.app.Activity; 41import android.app.AlertDialog; 42import android.app.Dialog; 43import android.content.Context; 44import android.content.DialogInterface; 45import android.content.DialogInterface.OnDismissListener; 46import android.database.DataSetObserver; 47import android.graphics.Color; 48import android.graphics.Rect; 49import android.location.Address; 50import android.os.Handler; 51import android.os.Message; 52import android.text.format.Formatter; 53import android.view.ContextThemeWrapper; 54import android.view.LayoutInflater; 55import android.view.MotionEvent; 56import android.view.View; 57import android.view.ViewGroup; 58import android.view.View.MeasureSpec; 59import android.widget.BaseAdapter; 60import android.widget.ListView; 61import android.widget.TextView; 62 63import java.util.ArrayList; 64import java.util.Map.Entry; 65 66public class DialogDetailsView implements DetailsViewContainer { 67 @SuppressWarnings("unused") 68 private static final String TAG = "DialogDetailsView"; 69 70 private GalleryActivity mContext; 71 private DetailsAdapter mAdapter; 72 private MediaDetails mDetails; 73 private DetailsSource mSource; 74 private int mIndex; 75 private Dialog mDialog; 76 private int mLocationIndex; 77 private CloseListener mListener; 78 79 public DialogDetailsView(GalleryActivity activity, DetailsSource source) { 80 mContext = activity; 81 mSource = source; 82 } 83 84 public void show() { 85 reloadDetails(mSource.getIndex()); 86 mDialog.show(); 87 } 88 89 public void hide() { 90 mDialog.hide(); 91 } 92 93 public void reloadDetails(int indexHint) { 94 int index = mSource.findIndex(indexHint); 95 if (index == -1) return; 96 MediaDetails details = mSource.getDetails(); 97 if (details != null) { 98 if (mIndex == index && mDetails == details) return; 99 mIndex = index; 100 mDetails = details; 101 setDetails(details); 102 } 103 } 104 105 public boolean isVisible() { 106 return mDialog.isShowing(); 107 } 108 109 private void setDetails(MediaDetails details) { 110 mAdapter = new DetailsAdapter(details); 111 String title = String.format( 112 mContext.getAndroidContext().getString(R.string.details_title), 113 mIndex + 1, mSource.size()); 114 ListView detailsList = (ListView) LayoutInflater.from(mContext.getAndroidContext()).inflate( 115 R.layout.details_list, null, false); 116 detailsList.setAdapter(mAdapter); 117 mDialog = new AlertDialog.Builder((Activity) mContext) 118 .setView(detailsList) 119 .setTitle(title) 120 .setPositiveButton(R.string.close, new DialogInterface.OnClickListener() { 121 public void onClick(DialogInterface dialog, int whichButton) { 122 mDialog.dismiss(); 123 } 124 }) 125 .create(); 126 127 mDialog.setOnDismissListener(new OnDismissListener() { 128 public void onDismiss(DialogInterface dialog) { 129 if (mListener != null) { 130 mListener.onClose(); 131 } 132 } 133 }); 134 } 135 136 private class DetailsAdapter extends BaseAdapter implements AddressResolvingListener { 137 private ArrayList<String> mItems; 138 139 public DetailsAdapter(MediaDetails details) { 140 Context context = mContext.getAndroidContext(); 141 mItems = new ArrayList<String>(details.size()); 142 mLocationIndex = -1; 143 setDetails(context, details); 144 } 145 146 private void setDetails(Context context, MediaDetails details) { 147 for (Entry<Integer, Object> detail : details) { 148 String value; 149 switch (detail.getKey()) { 150 case MediaDetails.INDEX_LOCATION: { 151 double[] latlng = (double[]) detail.getValue(); 152 mLocationIndex = mItems.size(); 153 value = DetailsHelper.resolveAddress(mContext, latlng, this); 154 break; 155 } 156 case MediaDetails.INDEX_SIZE: { 157 value = Formatter.formatFileSize( 158 context, (Long) detail.getValue()); 159 break; 160 } 161 case MediaDetails.INDEX_WHITE_BALANCE: { 162 value = "1".equals(detail.getValue()) 163 ? context.getString(R.string.manual) 164 : context.getString(R.string.auto); 165 break; 166 } 167 case MediaDetails.INDEX_FLASH: { 168 MediaDetails.FlashState flash = 169 (MediaDetails.FlashState) detail.getValue(); 170 // TODO: camera doesn't fill in the complete values, show more information 171 // when it is fixed. 172 if (flash.isFlashFired()) { 173 value = context.getString(R.string.flash_on); 174 } else { 175 value = context.getString(R.string.flash_off); 176 } 177 break; 178 } 179 case MediaDetails.INDEX_EXPOSURE_TIME: { 180 value = (String) detail.getValue(); 181 double time = Double.valueOf(value); 182 if (time < 1.0f) { 183 value = String.format("1/%d", (int) (0.5f + 1 / time)); 184 } else { 185 int integer = (int) time; 186 time -= integer; 187 value = String.valueOf(integer) + "''"; 188 if (time > 0.0001) { 189 value += String.format(" 1/%d", (int) (0.5f + 1 / time)); 190 } 191 } 192 break; 193 } 194 default: { 195 Object valueObj = detail.getValue(); 196 // This shouldn't happen, log its key to help us diagnose the problem. 197 Utils.assertTrue(valueObj != null, "%s's value is Null", 198 DetailsHelper.getDetailsName(context, detail.getKey())); 199 value = valueObj.toString(); 200 } 201 } 202 int key = detail.getKey(); 203 if (details.hasUnit(key)) { 204 value = String.format("%s : %s %s", DetailsHelper.getDetailsName( 205 context, key), value, context.getString(details.getUnit(key))); 206 } else { 207 value = String.format("%s : %s", DetailsHelper.getDetailsName( 208 context, key), value); 209 } 210 mItems.add(value); 211 } 212 } 213 214 public boolean areAllItemsEnabled() { 215 return false; 216 } 217 218 public boolean isEnabled(int position) { 219 return false; 220 } 221 222 public int getCount() { 223 return mItems.size(); 224 } 225 226 public Object getItem(int position) { 227 return mDetails.getDetail(position); 228 } 229 230 public long getItemId(int position) { 231 return position; 232 } 233 234 public View getView(int position, View convertView, ViewGroup parent) { 235 TextView tv; 236 if (convertView == null) { 237 tv = (TextView) LayoutInflater.from(mContext.getAndroidContext()).inflate( 238 R.layout.details, parent, false); 239 } else { 240 tv = (TextView) convertView; 241 } 242 tv.setText(mItems.get(position)); 243 return tv; 244 } 245 246 public void onAddressAvailable(String address) { 247 mItems.set(mLocationIndex, address); 248 } 249 } 250 251 public void setCloseListener(CloseListener listener) { 252 mListener = listener; 253 } 254} 255