Merge "Prevent any SecurityExceptions on Uri resolution" into sc-dev
This commit is contained in:
@@ -47,6 +47,7 @@ import android.content.Intent;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.ColorMatrix;
|
import android.graphics.ColorMatrix;
|
||||||
import android.graphics.ColorMatrixColorFilter;
|
import android.graphics.ColorMatrixColorFilter;
|
||||||
|
import android.graphics.ImageDecoder;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
import android.graphics.text.LineBreaker;
|
import android.graphics.text.LineBreaker;
|
||||||
@@ -59,6 +60,7 @@ import android.text.TextUtils;
|
|||||||
import android.util.IconDrawableFactory;
|
import android.util.IconDrawableFactory;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
import android.util.Size;
|
||||||
import android.util.SizeF;
|
import android.util.SizeF;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
@@ -79,6 +81,7 @@ import com.android.systemui.people.widget.LaunchConversationActivity;
|
|||||||
import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
|
import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
|
||||||
import com.android.systemui.people.widget.PeopleTileKey;
|
import com.android.systemui.people.widget.PeopleTileKey;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -679,15 +682,24 @@ public class PeopleTileViewHelper {
|
|||||||
RemoteViews views = setViewForContentLayout(new RemoteViews(mContext.getPackageName(),
|
RemoteViews views = setViewForContentLayout(new RemoteViews(mContext.getPackageName(),
|
||||||
getLayoutForNotificationContent()));
|
getLayoutForNotificationContent()));
|
||||||
CharSequence sender = mTile.getNotificationSender();
|
CharSequence sender = mTile.getNotificationSender();
|
||||||
Uri image = mTile.getNotificationDataUri();
|
Uri imageUri = mTile.getNotificationDataUri();
|
||||||
if (image != null) {
|
if (imageUri != null) {
|
||||||
// TODO: Use NotificationInlineImageCache
|
|
||||||
views.setImageViewUri(R.id.image, image);
|
|
||||||
String newImageDescription = mContext.getString(
|
String newImageDescription = mContext.getString(
|
||||||
R.string.new_notification_image_content_description, mTile.getUserName());
|
R.string.new_notification_image_content_description, mTile.getUserName());
|
||||||
views.setContentDescription(R.id.image, newImageDescription);
|
views.setContentDescription(R.id.image, newImageDescription);
|
||||||
views.setViewVisibility(R.id.image, View.VISIBLE);
|
views.setViewVisibility(R.id.image, View.VISIBLE);
|
||||||
views.setViewVisibility(R.id.text_content, View.GONE);
|
views.setViewVisibility(R.id.text_content, View.GONE);
|
||||||
|
try {
|
||||||
|
Drawable drawable = resolveImage(imageUri, mContext);
|
||||||
|
Bitmap bitmap = convertDrawableToBitmap(drawable);
|
||||||
|
views.setImageViewBitmap(R.id.image, bitmap);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Could not decode image: " + e);
|
||||||
|
// If we couldn't load the image, show text that we have a new image.
|
||||||
|
views.setTextViewText(R.id.text_content, newImageDescription);
|
||||||
|
views.setViewVisibility(R.id.text_content, View.VISIBLE);
|
||||||
|
views.setViewVisibility(R.id.image, View.GONE);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setMaxLines(views, !TextUtils.isEmpty(sender));
|
setMaxLines(views, !TextUtils.isEmpty(sender));
|
||||||
CharSequence content = mTile.getNotificationContent();
|
CharSequence content = mTile.getNotificationContent();
|
||||||
@@ -722,6 +734,40 @@ public class PeopleTileViewHelper {
|
|||||||
return views;
|
return views;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Drawable resolveImage(Uri uri, Context context) throws IOException {
|
||||||
|
final ImageDecoder.Source source =
|
||||||
|
ImageDecoder.createSource(context.getContentResolver(), uri);
|
||||||
|
final Drawable drawable =
|
||||||
|
ImageDecoder.decodeDrawable(source, (decoder, info, s) -> {
|
||||||
|
onHeaderDecoded(decoder, info, s);
|
||||||
|
});
|
||||||
|
return drawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getPowerOfTwoForSampleRatio(double ratio) {
|
||||||
|
final int k = Integer.highestOneBit((int) Math.floor(ratio));
|
||||||
|
return Math.max(1, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info,
|
||||||
|
ImageDecoder.Source source) {
|
||||||
|
int widthInPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mWidth,
|
||||||
|
mContext.getResources().getDisplayMetrics());
|
||||||
|
int heightInPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mHeight,
|
||||||
|
mContext.getResources().getDisplayMetrics());
|
||||||
|
int maxIconSizeInPx = Math.max(widthInPx, heightInPx);
|
||||||
|
int minDimen = (int) (1.5 * Math.min(widthInPx, heightInPx));
|
||||||
|
if (minDimen < maxIconSizeInPx) {
|
||||||
|
maxIconSizeInPx = minDimen;
|
||||||
|
}
|
||||||
|
final Size size = info.getSize();
|
||||||
|
final int originalSize = Math.max(size.getHeight(), size.getWidth());
|
||||||
|
final double ratio = (originalSize > maxIconSizeInPx)
|
||||||
|
? originalSize * 1f / maxIconSizeInPx
|
||||||
|
: 1.0;
|
||||||
|
decoder.setTargetSampleSize(getPowerOfTwoForSampleRatio(ratio));
|
||||||
|
}
|
||||||
|
|
||||||
private void setContentDescriptionForNotificationTextContent(RemoteViews views,
|
private void setContentDescriptionForNotificationTextContent(RemoteViews views,
|
||||||
CharSequence content, CharSequence sender) {
|
CharSequence content, CharSequence sender) {
|
||||||
String newTextDescriptionWithNotificationContent = mContext.getString(
|
String newTextDescriptionWithNotificationContent = mContext.getString(
|
||||||
|
|||||||
@@ -375,7 +375,7 @@ public class PeopleSpaceWidgetManager {
|
|||||||
widgetSp.getInt(USER_ID, INVALID_USER_ID),
|
widgetSp.getInt(USER_ID, INVALID_USER_ID),
|
||||||
widgetSp.getString(PACKAGE_NAME, EMPTY_STRING));
|
widgetSp.getString(PACKAGE_NAME, EMPTY_STRING));
|
||||||
|
|
||||||
return getTileFromPersistentStorage(key, appWidgetId);
|
return getTileFromPersistentStorage(key, appWidgetId, /* supplementFromStorage= */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -383,7 +383,8 @@ public class PeopleSpaceWidgetManager {
|
|||||||
* If a {@link PeopleTileKey} is not provided, fetch one from {@link SharedPreferences}.
|
* If a {@link PeopleTileKey} is not provided, fetch one from {@link SharedPreferences}.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public PeopleSpaceTile getTileFromPersistentStorage(PeopleTileKey key, int appWidgetId) throws
|
public PeopleSpaceTile getTileFromPersistentStorage(PeopleTileKey key, int appWidgetId,
|
||||||
|
boolean supplementFromStorage) throws
|
||||||
PackageManager.NameNotFoundException {
|
PackageManager.NameNotFoundException {
|
||||||
if (!PeopleTileKey.isValid(key)) {
|
if (!PeopleTileKey.isValid(key)) {
|
||||||
Log.e(TAG, "PeopleTileKey invalid: " + key.toString());
|
Log.e(TAG, "PeopleTileKey invalid: " + key.toString());
|
||||||
@@ -412,7 +413,8 @@ public class PeopleSpaceWidgetManager {
|
|||||||
|
|
||||||
// Supplement with our storage.
|
// Supplement with our storage.
|
||||||
String contactUri = mSharedPrefs.getString(String.valueOf(appWidgetId), null);
|
String contactUri = mSharedPrefs.getString(String.valueOf(appWidgetId), null);
|
||||||
if (contactUri != null && storedTile.build().getContactUri() == null) {
|
if (supplementFromStorage && contactUri != null
|
||||||
|
&& storedTile.build().getContactUri() == null) {
|
||||||
if (DEBUG) Log.d(TAG, "Restore contact uri from storage: " + contactUri);
|
if (DEBUG) Log.d(TAG, "Restore contact uri from storage: " + contactUri);
|
||||||
storedTile.setContactUri(Uri.parse(contactUri));
|
storedTile.setContactUri(Uri.parse(contactUri));
|
||||||
}
|
}
|
||||||
@@ -811,7 +813,8 @@ public class PeopleSpaceWidgetManager {
|
|||||||
if (DEBUG) Log.d(TAG, "addNewWidget called with key for appWidgetId: " + appWidgetId);
|
if (DEBUG) Log.d(TAG, "addNewWidget called with key for appWidgetId: " + appWidgetId);
|
||||||
PeopleSpaceTile tile = null;
|
PeopleSpaceTile tile = null;
|
||||||
try {
|
try {
|
||||||
tile = getTileFromPersistentStorage(key, appWidgetId);
|
tile = getTileFromPersistentStorage(key, appWidgetId, /* supplementFromStorage= */
|
||||||
|
false);
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
Log.e(TAG, "Cannot add widget since app was uninstalled");
|
Log.e(TAG, "Cannot add widget since app was uninstalled");
|
||||||
return;
|
return;
|
||||||
@@ -850,7 +853,9 @@ public class PeopleSpaceWidgetManager {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.w(TAG, "Exception caching shortcut:" + e);
|
Log.w(TAG, "Exception caching shortcut:" + e);
|
||||||
}
|
}
|
||||||
updateAppWidgetOptionsAndView(appWidgetId, tile);
|
PeopleSpaceTile finalTile = tile;
|
||||||
|
mBgExecutor.execute(
|
||||||
|
() -> updateAppWidgetOptionsAndView(appWidgetId, finalTile));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Registers a conversation listener for {@code appWidgetId} if not already registered. */
|
/** Registers a conversation listener for {@code appWidgetId} if not already registered. */
|
||||||
|
|||||||
@@ -1125,7 +1125,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
|
|||||||
new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A));
|
new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A));
|
||||||
when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(channel);
|
when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(channel);
|
||||||
PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A);
|
PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A);
|
||||||
PeopleSpaceTile tile = mManager.getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT);
|
PeopleSpaceTile tile = mManager
|
||||||
|
.getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT, true);
|
||||||
assertThat(tile.getId()).isEqualTo(key.getShortcutId());
|
assertThat(tile.getId()).isEqualTo(key.getShortcutId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1133,7 +1134,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
|
|||||||
public void testGetPeopleTileFromPersistentStorageNoConversation() throws Exception {
|
public void testGetPeopleTileFromPersistentStorageNoConversation() throws Exception {
|
||||||
when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(null);
|
when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(null);
|
||||||
PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A);
|
PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A);
|
||||||
PeopleSpaceTile tile = mManager.getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT);
|
PeopleSpaceTile tile = mManager
|
||||||
|
.getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT, false);
|
||||||
assertThat(tile).isNull();
|
assertThat(tile).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user