From 8369df095a73a77b3715f8ae7ba06089cebca4ce Mon Sep 17 00:00:00 2001 From: Eric Erfanian Date: Wed, 3 May 2017 10:27:13 -0700 Subject: This change reflects the Dialer V10 RC00 branch. RC00 is based on: branch: dialer-android_release_branch/153304843.1 synced to: 153304843 following the instructions at go/dialer-aosp-release. In this release: * Removes final apache sources. * Uses native lite compilation. More drops will follow with subsequent release candidates until we reach our final v10 release, in cadence with our prebuilt drops. Test: TreeHugger, on device Change-Id: Ic9684057230f9b579c777820c746cd21bf45ec0f --- .../dialer/callcomposer/CallComposerActivity.java | 103 +++++----- .../callcomposer/CameraComposerFragment.java | 2 +- .../callcomposer/CopyAndResizeImageWorker.java | 70 +++++++ .../callcomposer/GalleryComposerFragment.java | 65 +++--- .../callcomposer/camera/ImagePersistTask.java | 6 +- .../cameraui/res/values-b+sr+Latn/strings.xml | 11 ++ .../callcomposer/nano/CallComposerContact.java | 220 --------------------- .../callcomposer/proto/call_composer_contact.proto | 18 ++ .../callcomposer/res/values-b+sr+Latn/strings.xml | 33 ++++ .../dialer/callcomposer/util/BitmapResizer.java | 67 +++++++ .../callcomposer/util/CopyAndResizeImageTask.java | 124 ------------ 11 files changed, 297 insertions(+), 422 deletions(-) create mode 100644 java/com/android/dialer/callcomposer/CopyAndResizeImageWorker.java create mode 100644 java/com/android/dialer/callcomposer/cameraui/res/values-b+sr+Latn/strings.xml delete mode 100644 java/com/android/dialer/callcomposer/nano/CallComposerContact.java create mode 100644 java/com/android/dialer/callcomposer/proto/call_composer_contact.proto create mode 100644 java/com/android/dialer/callcomposer/res/values-b+sr+Latn/strings.xml create mode 100644 java/com/android/dialer/callcomposer/util/BitmapResizer.java delete mode 100644 java/com/android/dialer/callcomposer/util/CopyAndResizeImageTask.java (limited to 'java/com/android/dialer/callcomposer') diff --git a/java/com/android/dialer/callcomposer/CallComposerActivity.java b/java/com/android/dialer/callcomposer/CallComposerActivity.java index 3c0beb101..e8ca72e97 100644 --- a/java/com/android/dialer/callcomposer/CallComposerActivity.java +++ b/java/com/android/dialer/callcomposer/CallComposerActivity.java @@ -25,7 +25,6 @@ import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; @@ -50,28 +49,25 @@ import android.widget.RelativeLayout; import android.widget.TextView; import com.android.contacts.common.ContactPhotoManager; import com.android.dialer.callcomposer.CallComposerFragment.CallComposerListener; -import com.android.dialer.callcomposer.nano.CallComposerContact; -import com.android.dialer.callcomposer.util.CopyAndResizeImageTask; -import com.android.dialer.callcomposer.util.CopyAndResizeImageTask.Callback; +import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentBuilder; -import com.android.dialer.callintent.nano.CallInitiationType; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.common.UiUtil; +import com.android.dialer.common.concurrent.DialerExecutors; import com.android.dialer.constants.Constants; import com.android.dialer.enrichedcall.EnrichedCallComponent; import com.android.dialer.enrichedcall.EnrichedCallManager; import com.android.dialer.enrichedcall.EnrichedCallManager.State; import com.android.dialer.enrichedcall.Session; import com.android.dialer.enrichedcall.extensions.StateExtension; +import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; -import com.android.dialer.logging.nano.DialerImpression; import com.android.dialer.multimedia.MultimediaData; -import com.android.dialer.protos.ProtoParsers; import com.android.dialer.telecom.TelecomUtil; import com.android.dialer.util.ViewUtil; import com.android.dialer.widget.DialerToolbar; -import com.google.protobuf.nano.InvalidProtocolBufferNanoException; +import com.google.protobuf.InvalidProtocolBufferException; import java.io.File; /** @@ -133,7 +129,7 @@ public class CallComposerActivity extends AppCompatActivity public static Intent newIntent(Context context, CallComposerContact contact) { Intent intent = new Intent(context, CallComposerActivity.class); - ProtoParsers.put(intent, ARG_CALL_COMPOSER_CONTACT, contact); + intent.putExtra(ARG_CALL_COMPOSER_CONTACT, contact.toByteArray()); return intent; } @@ -195,7 +191,7 @@ public class CallComposerActivity extends AppCompatActivity runEntranceAnimation(); }); - setMediaIconSelected(0); + setMediaIconSelected(currentIndex); } @Override @@ -204,11 +200,11 @@ public class CallComposerActivity extends AppCompatActivity getEnrichedCallManager().registerStateChangedListener(this); if (sessionId == Session.NO_SESSION_ID) { LogUtil.i("CallComposerActivity.onResume", "creating new session"); - sessionId = getEnrichedCallManager().startCallComposerSession(contact.number); + sessionId = getEnrichedCallManager().startCallComposerSession(contact.getNumber()); } else if (getEnrichedCallManager().getSession(sessionId) == null) { LogUtil.i( "CallComposerActivity.onResume", "session closed while activity paused, creating new"); - sessionId = getEnrichedCallManager().startCallComposerSession(contact.number); + sessionId = getEnrichedCallManager().startCallComposerSession(contact.getNumber()); } else { LogUtil.i("CallComposerActivity.onResume", "session still open, using old"); } @@ -294,29 +290,28 @@ public class CallComposerActivity extends AppCompatActivity GalleryComposerFragment galleryComposerFragment = (GalleryComposerFragment) fragment; // If the current data is not a copy, make one. if (!galleryComposerFragment.selectedDataIsCopy()) { - new CopyAndResizeImageTask( - CallComposerActivity.this, - galleryComposerFragment.getGalleryData().getFileUri(), - new Callback() { - @Override - public void onCopySuccessful(File file, String mimeType) { - Uri shareableUri = - FileProvider.getUriForFile( - CallComposerActivity.this, - Constants.get().getFileProviderAuthority(), - file); - - builder.setImage(grantUriPermission(shareableUri), mimeType); - placeRCSCall(builder); - } - - @Override - public void onCopyFailed(Throwable throwable) { - // TODO(b/34279096) - gracefully handle message failure - LogUtil.e("CallComposerActivity.onCopyFailed", "copy Failed", throwable); - } + DialerExecutors.createUiTaskBuilder( + getFragmentManager(), + "copyAndResizeImageToSend", + new CopyAndResizeImageWorker(this.getApplicationContext())) + .onSuccess( + output -> { + Uri shareableUri = + FileProvider.getUriForFile( + CallComposerActivity.this, + Constants.get().getFileProviderAuthority(), + output.first); + + builder.setImage(grantUriPermission(shareableUri), output.second); + placeRCSCall(builder); + }) + .onFailure( + throwable -> { + // TODO(b/34279096) - gracefully handle message failure + LogUtil.e("CallComposerActivity.onCopyFailed", "copy Failed", throwable); }) - .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + .build() + .executeParallel(galleryComposerFragment.getGalleryData().getFileUri()); } else { Uri shareableUri = FileProvider.getUriForFile( @@ -355,7 +350,8 @@ public class CallComposerActivity extends AppCompatActivity Logger.get(this).logImpression(DialerImpression.Type.CALL_COMPOSER_ACTIVITY_PLACE_RCS_CALL); getEnrichedCallManager().sendCallComposerData(sessionId, builder.build()); TelecomUtil.placeCall( - this, new CallIntentBuilder(contact.number, CallInitiationType.Type.CALL_COMPOSER).build()); + this, + new CallIntentBuilder(contact.getNumber(), CallInitiationType.Type.CALL_COMPOSER).build()); setResult(RESULT_OK); finish(); } @@ -461,13 +457,15 @@ public class CallComposerActivity extends AppCompatActivity byte[] bytes = Base64.decode(arguments.getString(ARG_CALL_COMPOSER_CONTACT), Base64.DEFAULT); try { contact = CallComposerContact.parseFrom(bytes); - } catch (InvalidProtocolBufferNanoException e) { + } catch (InvalidProtocolBufferException e) { Assert.fail(e.toString()); } } else { - contact = - ProtoParsers.getFromInstanceState( - arguments, ARG_CALL_COMPOSER_CONTACT, new CallComposerContact()); + try { + contact = CallComposerContact.parseFrom(arguments.getByteArray(ARG_CALL_COMPOSER_CONTACT)); + } catch (InvalidProtocolBufferException e) { + throw Assert.createIllegalStateFailException(e.toString()); + } } updateContactInfo(); } @@ -480,22 +478,24 @@ public class CallComposerActivity extends AppCompatActivity /** Populates the contact info fields based on the current contact information. */ private void updateContactInfo() { ContactPhotoManager.getInstance(this) - .loadDialerThumbnail( + .loadDialerThumbnailOrPhoto( contactPhoto, - contact.contactUri == null ? null : Uri.parse(contact.contactUri), - contact.photoId, - contact.nameOrNumber, - contact.contactType); - - nameView.setText(contact.nameOrNumber); - toolbar.setTitle(contact.nameOrNumber); - if (!TextUtils.isEmpty(contact.numberLabel) && !TextUtils.isEmpty(contact.displayNumber)) { + contact.hasContactUri() ? Uri.parse(contact.getContactUri()) : null, + contact.getPhotoId(), + contact.hasPhotoUri() ? Uri.parse(contact.getPhotoUri()) : null, + contact.getNameOrNumber(), + contact.getContactType()); + + nameView.setText(contact.getNameOrNumber()); + toolbar.setTitle(contact.getNameOrNumber()); + if (!TextUtils.isEmpty(contact.getNumberLabel()) + && !TextUtils.isEmpty(contact.getDisplayNumber())) { numberView.setVisibility(View.VISIBLE); String secondaryInfo = getString( com.android.contacts.common.R.string.call_subject_type_and_number, - contact.numberLabel, - contact.displayNumber); + contact.getNumberLabel(), + contact.getDisplayNumber()); numberView.setText(secondaryInfo); toolbar.setSubtitle(secondaryInfo); } else { @@ -663,7 +663,8 @@ public class CallComposerActivity extends AppCompatActivity } private void setFailedResultAndFinish() { - setResult(RESULT_FIRST_USER, new Intent().putExtra(KEY_CONTACT_NAME, contact.nameOrNumber)); + setResult( + RESULT_FIRST_USER, new Intent().putExtra(KEY_CONTACT_NAME, contact.getNameOrNumber())); finish(); } diff --git a/java/com/android/dialer/callcomposer/CameraComposerFragment.java b/java/com/android/dialer/callcomposer/CameraComposerFragment.java index ceefc068e..f65207fa3 100644 --- a/java/com/android/dialer/callcomposer/CameraComposerFragment.java +++ b/java/com/android/dialer/callcomposer/CameraComposerFragment.java @@ -48,8 +48,8 @@ import com.android.dialer.callcomposer.camera.camerafocus.RenderOverlay; import com.android.dialer.callcomposer.cameraui.CameraMediaChooserView; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; +import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; -import com.android.dialer.logging.nano.DialerImpression; import com.android.dialer.util.PermissionsUtil; /** Fragment used to compose call with image from the user's camera. */ diff --git a/java/com/android/dialer/callcomposer/CopyAndResizeImageWorker.java b/java/com/android/dialer/callcomposer/CopyAndResizeImageWorker.java new file mode 100644 index 000000000..aeb8e0388 --- /dev/null +++ b/java/com/android/dialer/callcomposer/CopyAndResizeImageWorker.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dialer.callcomposer; + +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Bitmap.CompressFormat; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Build.VERSION_CODES; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.util.Pair; +import com.android.dialer.callcomposer.util.BitmapResizer; +import com.android.dialer.common.Assert; +import com.android.dialer.common.concurrent.DialerExecutor.Worker; +import com.android.dialer.util.DialerUtils; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; + +/** Task for copying and resizing images to be shared with RCS process. */ +@TargetApi(VERSION_CODES.M) +class CopyAndResizeImageWorker implements Worker> { + private static final String MIME_TYPE = "image/jpeg"; + + private final Context context; + + CopyAndResizeImageWorker(@NonNull Context context) { + this.context = Assert.isNotNull(context); + } + + /** + * @param input The input Uri is expected to be a image openable by {@link + * android.content.ContentResolver#openInputStream(Uri)}. + * @return a Pair where the File contains the resized image, and the String is the result File's + * MIME type. + */ + @Nullable + @Override + public Pair doInBackground(@Nullable Uri input) throws Throwable { + try (InputStream inputStream = context.getContentResolver().openInputStream(input)) { + Bitmap bitmap = BitmapFactory.decodeStream(inputStream); + bitmap = BitmapResizer.resizeForEnrichedCalling(bitmap); + + File outputFile = DialerUtils.createShareableFile(context); + try (OutputStream outputStream = new FileOutputStream(outputFile)) { + // Encode images to jpeg as it is better for camera pictures which we expect to be sending + bitmap.compress(CompressFormat.JPEG, 80, outputStream); + return new Pair<>(outputFile, MIME_TYPE); + } + } + } +} diff --git a/java/com/android/dialer/callcomposer/GalleryComposerFragment.java b/java/com/android/dialer/callcomposer/GalleryComposerFragment.java index 1d684a2d3..01e067440 100644 --- a/java/com/android/dialer/callcomposer/GalleryComposerFragment.java +++ b/java/com/android/dialer/callcomposer/GalleryComposerFragment.java @@ -28,6 +28,7 @@ import android.os.Parcelable; import android.provider.Settings; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.ContextCompat; import android.support.v4.content.CursorLoader; @@ -39,13 +40,14 @@ import android.view.ViewGroup; import android.widget.GridView; import android.widget.ImageView; import android.widget.TextView; -import com.android.dialer.callcomposer.util.CopyAndResizeImageTask; -import com.android.dialer.callcomposer.util.CopyAndResizeImageTask.Callback; +import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; +import com.android.dialer.common.concurrent.DefaultDialerExecutorFactory; +import com.android.dialer.common.concurrent.DialerExecutor; +import com.android.dialer.common.concurrent.DialerExecutorFactory; +import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; -import com.android.dialer.logging.nano.DialerImpression; import com.android.dialer.util.PermissionsUtil; -import java.io.File; import java.util.ArrayList; import java.util.List; @@ -60,6 +62,8 @@ public class GalleryComposerFragment extends CallComposerFragment private static final int RESULT_LOAD_IMAGE = 1; private static final int RESULT_OPEN_SETTINGS = 2; + private DialerExecutorFactory executorFactory = new DefaultDialerExecutorFactory(); + private GalleryGridAdapter adapter; private GridView galleryGridView; private View permissionView; @@ -71,10 +75,17 @@ public class GalleryComposerFragment extends CallComposerFragment private boolean selectedDataIsCopy; private List insertedImages = new ArrayList<>(); + private DialerExecutor copyAndResizeImage; + public static GalleryComposerFragment newInstance() { return new GalleryComposerFragment(); } + @VisibleForTesting + void setExecutorFactory(@NonNull DialerExecutorFactory executorFactory) { + this.executorFactory = Assert.isNotNull(executorFactory); + } + @Nullable @Override public View onCreateView( @@ -107,6 +118,32 @@ public class GalleryComposerFragment extends CallComposerFragment return view; } + @Override + public void onActivityCreated(@Nullable Bundle bundle) { + super.onActivityCreated(bundle); + + copyAndResizeImage = + executorFactory + .createUiTaskBuilder( + getActivity().getFragmentManager(), + "copyAndResizeImage", + new CopyAndResizeImageWorker(getActivity().getApplicationContext())) + .onSuccess( + output -> { + GalleryGridItemData data1 = + adapter.insertEntry(output.first.getAbsolutePath(), output.second); + insertedImages.add(0, data1); + setSelected(data1, true); + }) + .onFailure( + throwable -> { + // TODO(b/34279096) - gracefully handle message failure + LogUtil.e( + "GalleryComposerFragment.onFailure", "data preparation failed", throwable); + }) + .build(); + } + private void setupGallery() { adapter = new GalleryGridAdapter(getContext(), null, this); galleryGridView.setAdapter(adapter); @@ -264,25 +301,7 @@ public class GalleryComposerFragment extends CallComposerFragment // This should never happen, but just in case.. // Guard against null uri cases for when the activity returns a null/invalid intent. if (url != null) { - new CopyAndResizeImageTask( - getContext(), - Uri.parse(url), - new Callback() { - @Override - public void onCopySuccessful(File file, String mimeType) { - GalleryGridItemData data = adapter.insertEntry(file.getAbsolutePath(), mimeType); - insertedImages.add(0, data); - setSelected(data, true); - } - - @Override - public void onCopyFailed(Throwable throwable) { - // TODO(b/34279096) - gracefully handle message failure - LogUtil.e( - "GalleryComposerFragment.onFailure", "Data preparation failed", throwable); - } - }) - .execute(); + copyAndResizeImage.executeParallel(Uri.parse(url)); } else { // TODO(b/34279096) - gracefully handle message failure } diff --git a/java/com/android/dialer/callcomposer/camera/ImagePersistTask.java b/java/com/android/dialer/callcomposer/camera/ImagePersistTask.java index 80921cdd8..31751e536 100644 --- a/java/com/android/dialer/callcomposer/camera/ImagePersistTask.java +++ b/java/com/android/dialer/callcomposer/camera/ImagePersistTask.java @@ -27,7 +27,7 @@ import android.os.Build.VERSION_CODES; import android.support.v4.content.FileProvider; import com.android.dialer.callcomposer.camera.exif.ExifInterface; import com.android.dialer.callcomposer.camera.exif.ExifTag; -import com.android.dialer.callcomposer.util.CopyAndResizeImageTask; +import com.android.dialer.callcomposer.util.BitmapResizer; import com.android.dialer.common.Assert; import com.android.dialer.common.concurrent.FallibleAsyncTask; import com.android.dialer.constants.Constants; @@ -75,7 +75,7 @@ public class ImagePersistTask extends FallibleAsyncTask { writeClippedBitmap(outputStream); } else { Bitmap bitmap = BitmapFactory.decodeByteArray(mBytes, 0, mBytes.length); - bitmap = CopyAndResizeImageTask.resizeForEnrichedCalling(bitmap); + bitmap = BitmapResizer.resizeForEnrichedCalling(bitmap); bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream); } } @@ -131,7 +131,7 @@ public class ImagePersistTask extends FallibleAsyncTask { matrix.postTranslate(-offsetLeft, -offsetTop); clippedBitmapCanvas.drawBitmap(bitmap, matrix, null /* paint */); clippedBitmapCanvas.save(); - clippedBitmap = CopyAndResizeImageTask.resizeForEnrichedCalling(clippedBitmap); + clippedBitmap = BitmapResizer.resizeForEnrichedCalling(clippedBitmap); // EXIF data can take a big chunk of the file size and is often cleared by the // carrier, only store orientation since that's critical final ExifTag orientationTag = exifInterface.getTag(ExifInterface.TAG_ORIENTATION); diff --git a/java/com/android/dialer/callcomposer/cameraui/res/values-b+sr+Latn/strings.xml b/java/com/android/dialer/callcomposer/cameraui/res/values-b+sr+Latn/strings.xml new file mode 100644 index 000000000..aad8d9dd8 --- /dev/null +++ b/java/com/android/dialer/callcomposer/cameraui/res/values-b+sr+Latn/strings.xml @@ -0,0 +1,11 @@ + + + "Pređite na prikaz kamere preko celog ekrana" + "Dugme sad aktivira prednju kameru" + "Dugme sad aktivira zadnju kameru" + "Zaustavite snimanje videa" + "Koristimo prednju kameru" + "Koristimo zadnju kameru" + "Snimite sliku" + diff --git a/java/com/android/dialer/callcomposer/nano/CallComposerContact.java b/java/com/android/dialer/callcomposer/nano/CallComposerContact.java deleted file mode 100644 index dcda571e2..000000000 --- a/java/com/android/dialer/callcomposer/nano/CallComposerContact.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Generated by the protocol buffer compiler. DO NOT EDIT! - -package com.android.dialer.callcomposer.nano; - -/** This file is autogenerated, but javadoc required. */ -@SuppressWarnings("hiding") -public final class CallComposerContact - extends com.google.protobuf.nano.ExtendableMessageNano { - - private static volatile CallComposerContact[] _emptyArray; - public static CallComposerContact[] emptyArray() { - // Lazily initializes the empty array - if (_emptyArray == null) { - synchronized (com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) { - if (_emptyArray == null) { - _emptyArray = new CallComposerContact[0]; - } - } - } - return _emptyArray; - } - - // optional fixed64 photo_id = 1; - public long photoId; - - // optional string photo_uri = 2; - public java.lang.String photoUri; - - // optional string contact_uri = 3; - public java.lang.String contactUri; - - // optional string name_or_number = 4; - public java.lang.String nameOrNumber; - - // optional string number = 6; - public java.lang.String number; - - // optional string display_number = 7; - public java.lang.String displayNumber; - - // optional string number_label = 8; - public java.lang.String numberLabel; - - // optional int32 contact_type = 9; - public int contactType; - - // @@protoc_insertion_point(class_scope:com.android.dialer.callcomposer.CallComposerContact) - - public CallComposerContact() { - clear(); - } - - public CallComposerContact clear() { - photoId = 0L; - photoUri = ""; - contactUri = ""; - nameOrNumber = ""; - number = ""; - displayNumber = ""; - numberLabel = ""; - contactType = 0; - unknownFieldData = null; - cachedSize = -1; - return this; - } - - @Override - public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output) - throws java.io.IOException { - if (this.photoId != 0L) { - output.writeFixed64(1, this.photoId); - } - if (this.photoUri != null && !this.photoUri.equals("")) { - output.writeString(2, this.photoUri); - } - if (this.contactUri != null && !this.contactUri.equals("")) { - output.writeString(3, this.contactUri); - } - if (this.nameOrNumber != null && !this.nameOrNumber.equals("")) { - output.writeString(4, this.nameOrNumber); - } - if (this.number != null && !this.number.equals("")) { - output.writeString(6, this.number); - } - if (this.displayNumber != null && !this.displayNumber.equals("")) { - output.writeString(7, this.displayNumber); - } - if (this.numberLabel != null && !this.numberLabel.equals("")) { - output.writeString(8, this.numberLabel); - } - if (this.contactType != 0) { - output.writeInt32(9, this.contactType); - } - super.writeTo(output); - } - - @Override - protected int computeSerializedSize() { - int size = super.computeSerializedSize(); - if (this.photoId != 0L) { - size += - com.google.protobuf.nano.CodedOutputByteBufferNano.computeFixed64Size(1, this.photoId); - } - if (this.photoUri != null && !this.photoUri.equals("")) { - size += - com.google.protobuf.nano.CodedOutputByteBufferNano.computeStringSize(2, this.photoUri); - } - if (this.contactUri != null && !this.contactUri.equals("")) { - size += - com.google.protobuf.nano.CodedOutputByteBufferNano.computeStringSize(3, this.contactUri); - } - if (this.nameOrNumber != null && !this.nameOrNumber.equals("")) { - size += - com.google.protobuf.nano.CodedOutputByteBufferNano.computeStringSize( - 4, this.nameOrNumber); - } - if (this.number != null && !this.number.equals("")) { - size += com.google.protobuf.nano.CodedOutputByteBufferNano.computeStringSize(6, this.number); - } - if (this.displayNumber != null && !this.displayNumber.equals("")) { - size += - com.google.protobuf.nano.CodedOutputByteBufferNano.computeStringSize( - 7, this.displayNumber); - } - if (this.numberLabel != null && !this.numberLabel.equals("")) { - size += - com.google.protobuf.nano.CodedOutputByteBufferNano.computeStringSize(8, this.numberLabel); - } - if (this.contactType != 0) { - size += - com.google.protobuf.nano.CodedOutputByteBufferNano.computeInt32Size(9, this.contactType); - } - return size; - } - - @Override - public CallComposerContact mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano input) - throws java.io.IOException { - while (true) { - int tag = input.readTag(); - switch (tag) { - case 0: - return this; - default: - { - if (!super.storeUnknownField(input, tag)) { - return this; - } - break; - } - case 9: - { - this.photoId = input.readFixed64(); - break; - } - case 18: - { - this.photoUri = input.readString(); - break; - } - case 26: - { - this.contactUri = input.readString(); - break; - } - case 34: - { - this.nameOrNumber = input.readString(); - break; - } - case 50: - { - this.number = input.readString(); - break; - } - case 58: - { - this.displayNumber = input.readString(); - break; - } - case 66: - { - this.numberLabel = input.readString(); - break; - } - case 72: - { - this.contactType = input.readInt32(); - break; - } - } - } - } - - public static CallComposerContact parseFrom(byte[] data) - throws com.google.protobuf.nano.InvalidProtocolBufferNanoException { - return com.google.protobuf.nano.MessageNano.mergeFrom(new CallComposerContact(), data); - } - - public static CallComposerContact parseFrom( - com.google.protobuf.nano.CodedInputByteBufferNano input) throws java.io.IOException { - return new CallComposerContact().mergeFrom(input); - } -} diff --git a/java/com/android/dialer/callcomposer/proto/call_composer_contact.proto b/java/com/android/dialer/callcomposer/proto/call_composer_contact.proto new file mode 100644 index 000000000..99766aac5 --- /dev/null +++ b/java/com/android/dialer/callcomposer/proto/call_composer_contact.proto @@ -0,0 +1,18 @@ +syntax = "proto2"; + +option java_package = "com.android.dialer.callcomposer"; +option java_multiple_files = true; +option optimize_for = LITE_RUNTIME; + +package com.android.dialer.callcomposer; + +message CallComposerContact { + optional fixed64 photo_id = 1; + optional string photo_uri = 2; + optional string contact_uri = 3; + optional string name_or_number = 4; + optional string number = 6; + optional string display_number = 7; + optional string number_label = 8; + optional int32 contact_type = 9; +} diff --git a/java/com/android/dialer/callcomposer/res/values-b+sr+Latn/strings.xml b/java/com/android/dialer/callcomposer/res/values-b+sr+Latn/strings.xml new file mode 100644 index 000000000..c357d506f --- /dev/null +++ b/java/com/android/dialer/callcomposer/res/values-b+sr+Latn/strings.xml @@ -0,0 +1,33 @@ + + + + + "Hitno je! Javi se!" + "Želiš da ćaskaš?" + "Kratko pitanje…" + "Napišite prilagođenu poruku" + "Pošalji i pozovi" + "Deli i pozovi" + "slika, %1$tB %1$te %1$tY %1$tl %1$tM %1$tp" + "slika" + "Slikajte" + "Učitavanje slike sa kamere nije uspelo" + "Dozvoli" + "Odobrite pristup Kameri da biste snimili sliku" + "Odobrite pristup Medijima da biste delili sliku" + diff --git a/java/com/android/dialer/callcomposer/util/BitmapResizer.java b/java/com/android/dialer/callcomposer/util/BitmapResizer.java new file mode 100644 index 000000000..658462def --- /dev/null +++ b/java/com/android/dialer/callcomposer/util/BitmapResizer.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dialer.callcomposer.util; + +import android.graphics.Bitmap; +import android.support.annotation.VisibleForTesting; +import com.android.dialer.common.Assert; +import com.android.dialer.common.LogUtil; + +/** Utility class for resizing images before sending them as enriched call attachments. */ +public final class BitmapResizer { + @VisibleForTesting static final int MAX_OUTPUT_RESOLUTION = 640; + + /** + * Returns a bitmap that is a resized version of the parameter image. The image will only be + * resized down and sized to be appropriate for an enriched call. + */ + public static Bitmap resizeForEnrichedCalling(Bitmap image) { + Assert.isWorkerThread(); + + int width = image.getWidth(); + int height = image.getHeight(); + + LogUtil.i( + "BitmapResizer.resizeForEnrichedCalling", "starting height: %d, width: %d", height, width); + + if (width <= MAX_OUTPUT_RESOLUTION && height <= MAX_OUTPUT_RESOLUTION) { + LogUtil.i("BitmapResizer.resizeForEnrichedCalling", "no resizing needed"); + return image; + } + + if (width > height) { + // landscape + float ratio = width / (float) MAX_OUTPUT_RESOLUTION; + width = MAX_OUTPUT_RESOLUTION; + height = (int) (height / ratio); + } else if (height > width) { + // portrait + float ratio = height / (float) MAX_OUTPUT_RESOLUTION; + height = MAX_OUTPUT_RESOLUTION; + width = (int) (width / ratio); + } else { + // square + height = MAX_OUTPUT_RESOLUTION; + width = MAX_OUTPUT_RESOLUTION; + } + + LogUtil.i( + "BitmapResizer.resizeForEnrichedCalling", "ending height: %d, width: %d", height, width); + + return Bitmap.createScaledBitmap(image, width, height, true); + } +} diff --git a/java/com/android/dialer/callcomposer/util/CopyAndResizeImageTask.java b/java/com/android/dialer/callcomposer/util/CopyAndResizeImageTask.java deleted file mode 100644 index 81511d274..000000000 --- a/java/com/android/dialer/callcomposer/util/CopyAndResizeImageTask.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dialer.callcomposer.util; - -import android.annotation.TargetApi; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Bitmap.CompressFormat; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.Build.VERSION_CODES; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import com.android.dialer.common.Assert; -import com.android.dialer.common.LogUtil; -import com.android.dialer.common.concurrent.FallibleAsyncTask; -import com.android.dialer.util.DialerUtils; -import java.io.File; -import java.io.FileOutputStream; -import java.io.OutputStream; - -/** Task for copying and resizing images to be shared with RCS process. */ -@TargetApi(VERSION_CODES.M) -public class CopyAndResizeImageTask extends FallibleAsyncTask { - public static final int MAX_OUTPUT_RESOLUTION = 640; - private static final String MIME_TYPE = "image/jpeg"; - - private final Context context; - private final Uri uri; - private final Callback callback; - - public CopyAndResizeImageTask( - @NonNull Context context, @NonNull Uri uri, @NonNull Callback callback) { - this.context = Assert.isNotNull(context); - this.uri = Assert.isNotNull(uri); - this.callback = Assert.isNotNull(callback); - } - - @Nullable - @Override - protected File doInBackgroundFallible(Void... params) throws Throwable { - Bitmap bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri)); - bitmap = resizeForEnrichedCalling(bitmap); - - File outputFile = DialerUtils.createShareableFile(context); - try (OutputStream outputStream = new FileOutputStream(outputFile)) { - // Encode images to jpeg as it is better for camera pictures which we expect to be sending - bitmap.compress(CompressFormat.JPEG, 80, outputStream); - return outputFile; - } - } - - @Override - protected void onPostExecute(FallibleTaskResult result) { - if (result.isFailure()) { - callback.onCopyFailed(result.getThrowable()); - } else { - callback.onCopySuccessful(result.getResult(), MIME_TYPE); - } - } - - public static Bitmap resizeForEnrichedCalling(Bitmap image) { - Assert.isWorkerThread(); - - int width = image.getWidth(); - int height = image.getHeight(); - - LogUtil.i( - "CopyAndResizeImageTask.resizeForEnrichedCalling", - "starting height: %d, width: %d", - height, - width); - - if (width <= MAX_OUTPUT_RESOLUTION && height <= MAX_OUTPUT_RESOLUTION) { - LogUtil.i("CopyAndResizeImageTask.resizeForEnrichedCalling", "no resizing needed"); - return image; - } - - if (width > height) { - // landscape - float ratio = width / (float) MAX_OUTPUT_RESOLUTION; - width = MAX_OUTPUT_RESOLUTION; - height = (int) (height / ratio); - } else if (height > width) { - // portrait - float ratio = height / (float) MAX_OUTPUT_RESOLUTION; - height = MAX_OUTPUT_RESOLUTION; - width = (int) (width / ratio); - } else { - // square - height = MAX_OUTPUT_RESOLUTION; - width = MAX_OUTPUT_RESOLUTION; - } - - LogUtil.i( - "CopyAndResizeImageTask.resizeForEnrichedCalling", - "ending height: %d, width: %d", - height, - width); - - return Bitmap.createScaledBitmap(image, width, height, true); - } - - /** Callback for callers to know when the task has finished */ - public interface Callback { - void onCopySuccessful(File file, String mimeType); - - void onCopyFailed(Throwable throwable); - } -} -- cgit v1.2.3