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