1 /* 2 * Copyright (C) 2015 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.messaging.ui.photoviewer; 18 19 import android.Manifest; 20 import android.app.Activity; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.database.Cursor; 24 import android.net.Uri; 25 import android.os.Bundle; 26 import androidx.fragment.app.FragmentManager; 27 import androidx.loader.content.Loader; 28 import android.text.TextUtils; 29 import android.view.Menu; 30 import android.view.MenuItem; 31 import android.widget.ShareActionProvider; 32 import android.widget.Toast; 33 34 import com.android.ex.photo.PhotoViewController; 35 import com.android.ex.photo.adapters.PhotoPagerAdapter; 36 import com.android.ex.photo.loaders.PhotoBitmapLoaderInterface.BitmapResult; 37 import com.android.messaging.R; 38 import com.android.messaging.datamodel.ConversationImagePartsView.PhotoViewQuery; 39 import com.android.messaging.datamodel.MediaScratchFileProvider; 40 import com.android.messaging.ui.conversation.ConversationFragment; 41 import com.android.messaging.util.Dates; 42 import com.android.messaging.util.LogUtil; 43 import com.android.messaging.util.OsUtil; 44 45 /** 46 * Customizations for the photoviewer to display conversation images in full screen. 47 */ 48 public class BuglePhotoViewController extends PhotoViewController { 49 private ShareActionProvider mShareActionProvider; 50 private MenuItem mShareItem; 51 private MenuItem mSaveItem; 52 BuglePhotoViewController(final ActivityInterface activity)53 public BuglePhotoViewController(final ActivityInterface activity) { 54 super(activity); 55 } 56 57 @Override onCreateBitmapLoader( final int id, final Bundle args, final String uri)58 public Loader<BitmapResult> onCreateBitmapLoader( 59 final int id, final Bundle args, final String uri) { 60 switch (id) { 61 case BITMAP_LOADER_AVATAR: 62 case BITMAP_LOADER_THUMBNAIL: 63 case BITMAP_LOADER_PHOTO: 64 return new BuglePhotoBitmapLoader(getActivity().getContext(), uri); 65 default: 66 LogUtil.e(LogUtil.BUGLE_TAG, 67 "Photoviewer unable to open bitmap loader with unknown id: " + id); 68 return null; 69 } 70 } 71 72 @Override updateActionBar()73 public void updateActionBar() { 74 final Cursor cursor = getCursorAtProperPosition(); 75 76 if (mSaveItem == null || cursor == null) { 77 // Load not finished, called from framework code before ready 78 return; 79 } 80 // Show the name as the title 81 mActionBarTitle = cursor.getString(PhotoViewQuery.INDEX_SENDER_FULL_NAME); 82 if (TextUtils.isEmpty(mActionBarTitle)) { 83 // If the name is not known, fall back to the phone number 84 mActionBarTitle = cursor.getString(PhotoViewQuery.INDEX_DISPLAY_DESTINATION); 85 } 86 87 // Show the timestamp as the subtitle 88 final long receivedTimestamp = cursor.getLong(PhotoViewQuery.INDEX_RECEIVED_TIMESTAMP); 89 mActionBarSubtitle = Dates.getMessageTimeString(receivedTimestamp).toString(); 90 91 setActionBarTitles(getActivity().getActionBarInterface()); 92 mSaveItem.setVisible(!isTempFile()); 93 94 updateShareActionProvider(); 95 } 96 updateShareActionProvider()97 private void updateShareActionProvider() { 98 final PhotoPagerAdapter adapter = getAdapter(); 99 final Cursor cursor = getCursorAtProperPosition(); 100 if (mShareActionProvider == null || mShareItem == null || adapter == null || 101 cursor == null) { 102 // Not enough stuff loaded to update the share action 103 return; 104 } 105 final String photoUri = adapter.getPhotoUri(cursor); 106 if (isTempFile()) { 107 mShareItem.setVisible(false); 108 return; 109 } 110 final String contentType = adapter.getContentType(cursor); 111 112 final Intent shareIntent = new Intent(); 113 shareIntent.setAction(Intent.ACTION_SEND); 114 shareIntent.setType(contentType); 115 shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(photoUri)); 116 mShareActionProvider.setShareIntent(shareIntent); 117 mShareItem.setVisible(true); 118 } 119 120 /** 121 * Checks whether the current photo is a temp file. A temp file can be deleted at any time, so 122 * we need to disable share and save options because the file may no longer be there. 123 */ isTempFile()124 private boolean isTempFile() { 125 final Cursor cursor = getCursorAtProperPosition(); 126 final Uri photoUri = Uri.parse(getAdapter().getPhotoUri(cursor)); 127 return MediaScratchFileProvider.isMediaScratchSpaceUri(photoUri); 128 } 129 130 @Override onCreateOptionsMenu(final Menu menu)131 public boolean onCreateOptionsMenu(final Menu menu) { 132 ((Activity) getActivity()).getMenuInflater().inflate(R.menu.photo_view_menu, menu); 133 134 // Get the ShareActionProvider 135 mShareItem = menu.findItem(R.id.action_share); 136 mShareActionProvider = (ShareActionProvider) mShareItem.getActionProvider(); 137 updateShareActionProvider(); 138 139 mSaveItem = menu.findItem(R.id.action_save); 140 return true; 141 } 142 143 @Override onPrepareOptionsMenu(final Menu menu)144 public boolean onPrepareOptionsMenu(final Menu menu) { 145 return !mIsEmpty; 146 } 147 148 @Override onOptionsItemSelected(final MenuItem item)149 public boolean onOptionsItemSelected(final MenuItem item) { 150 if (item.getItemId() == R.id.action_save) { 151 if (OsUtil.hasStoragePermission()) { 152 final PhotoPagerAdapter adapter = getAdapter(); 153 final Cursor cursor = getCursorAtProperPosition(); 154 if (cursor == null) { 155 final Context context = getActivity().getContext(); 156 final String error = context.getResources().getQuantityString( 157 R.plurals.attachment_save_error, 1, 1); 158 Toast.makeText(context, error, Toast.LENGTH_SHORT).show(); 159 return true; 160 } 161 final String photoUri = adapter.getPhotoUri(cursor); 162 new ConversationFragment.SaveAttachmentTask(((Activity) getActivity()), 163 Uri.parse(photoUri), adapter.getContentType(cursor)).executeOnThreadPool(); 164 } else { 165 ((Activity)getActivity()).requestPermissions( 166 new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, 0); 167 } 168 return true; 169 } else { 170 return super.onOptionsItemSelected(item); 171 } 172 } 173 174 @Override createPhotoPagerAdapter(final Context context, final FragmentManager fm, final Cursor c, final float maxScale)175 public PhotoPagerAdapter createPhotoPagerAdapter(final Context context, 176 final FragmentManager fm, final Cursor c, final float maxScale) { 177 return new BuglePhotoPageAdapter(context, fm, c, maxScale, mDisplayThumbsFullScreen); 178 } 179 } 180