From 47d735be2c65c4e891bcc9b44d4f01b9a65ad102 Mon Sep 17 00:00:00 2001 From: "MINIPC\\frivaong" Date: Mon, 28 Sep 2026 23:44:47 +0900 Subject: [PATCH] Messaging: Meet Play memory/R8 rules, ship Q icon, and polish home chrome Co-authored-by: Cursor --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 1 + .../android/messaging/BugleApplication.java | 21 +++++++- .../datamodel/media/DecodedImageResource.java | 11 ++++- .../datamodel/media/EncodedImageResource.java | 44 ++++++++++++++--- .../media/NetworkUriImageRequest.java | 8 ++- .../ConversationListActivity.java | 2 + .../ConversationListItemView.java | 46 ++++++++++++++++-- .../ui/home/HomeCategoryAddModal.java | 13 ++++- .../android/messaging/util/ImageUtils.java | 40 +++++++++++++++ .../ic_launcher_foreground.png | Bin 0 -> 10744 bytes .../res/drawable/ic_launcher_background.xml | 25 +++++----- .../res/drawable/ic_launcher_foreground.xml | 34 ------------- .../res/drawable/ic_launcher_monochrome.xml | 21 ++------ .../res/layout/conversation_list_fragment.xml | 4 +- .../layout/conversation_list_item_view.xml | 1 - .../main/res/layout/home_category_add_tab.xml | 3 ++ proguard-release.flags | 2 - proguard.flags | 39 ++++++--------- 19 files changed, 209 insertions(+), 107 deletions(-) create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png delete mode 100644 app/src/main/res/drawable/ic_launcher_foreground.xml diff --git a/app/build.gradle b/app/build.gradle index ece4bc9..68ae539 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,6 +41,7 @@ android { buildTypes { release { minifyEnabled true + shrinkResources true signingConfig signingConfigs.release proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), rootProject.file('proguard-release.flags'), diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d40ae4b..557b420 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -91,6 +91,7 @@ android:allowBackup="false" android:appCategory="social" android:icon="@mipmap/ic_launcher" + android:roundIcon="@mipmap/ic_launcher" android:label="@string/app_name" android:localeConfig="@xml/locales_config" android:requestLegacyExternalStorage="true" diff --git a/app/src/main/java/com/android/messaging/BugleApplication.java b/app/src/main/java/com/android/messaging/BugleApplication.java index 4c2d796..83d1a1c 100644 --- a/app/src/main/java/com/android/messaging/BugleApplication.java +++ b/app/src/main/java/com/android/messaging/BugleApplication.java @@ -128,6 +128,18 @@ public class BugleApplication extends Application implements UncaughtExceptionHa Trace.endSection(); } + @Override + public void onTrimMemory(final int level) { + super.onTrimMemory(level); + if (level < TRIM_MEMORY_UI_HIDDEN) { + return; + } + if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) { + LogUtil.d(TAG, "BugleApplication.onTrimMemory " + level); + } + reclaimCachedBitmaps(); + } + @Override public void onLowMemory() { super.onLowMemory(); @@ -135,7 +147,14 @@ public class BugleApplication extends Application implements UncaughtExceptionHa if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) { LogUtil.d(TAG, "BugleApplication.onLowMemory"); } - Factory.get().reclaimMemory(); + reclaimCachedBitmaps(); + } + + private static void reclaimCachedBitmaps() { + final Factory factory = Factory.get(); + if (factory != null) { + factory.reclaimMemory(); + } } @Override diff --git a/app/src/main/java/com/android/messaging/datamodel/media/DecodedImageResource.java b/app/src/main/java/com/android/messaging/datamodel/media/DecodedImageResource.java index b79a815..4b477bb 100644 --- a/app/src/main/java/com/android/messaging/datamodel/media/DecodedImageResource.java +++ b/app/src/main/java/com/android/messaging/datamodel/media/DecodedImageResource.java @@ -211,7 +211,16 @@ public class DecodedImageResource extends ImageResource { } } byte[] encodedBytes = ImageUtils.bitmapToBytes(bitmap, COMPRESS_QUALITY); - return new EncodedImageResource(getKey(), encodedBytes, getOrientation()); + int desiredWidth = ImageRequest.UNSPECIFIED_SIZE; + int desiredHeight = ImageRequest.UNSPECIFIED_SIZE; + if (mOriginalImageRequest instanceof ImageRequest) { + final ImageRequestDescriptor descriptor = + ((ImageRequest) mOriginalImageRequest).getDescriptor(); + desiredWidth = descriptor.desiredWidth; + desiredHeight = descriptor.desiredHeight; + } + return new EncodedImageResource(getKey(), encodedBytes, getOrientation(), + desiredWidth, desiredHeight); } catch (Exception ex) { // Something went wrong during bitmap compression, fall back to just using the // original bitmap. diff --git a/app/src/main/java/com/android/messaging/datamodel/media/EncodedImageResource.java b/app/src/main/java/com/android/messaging/datamodel/media/EncodedImageResource.java index 0bc94e5..98d1906 100644 --- a/app/src/main/java/com/android/messaging/datamodel/media/EncodedImageResource.java +++ b/app/src/main/java/com/android/messaging/datamodel/media/EncodedImageResource.java @@ -17,11 +17,11 @@ package com.android.messaging.datamodel.media; import android.content.res.Resources; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; import com.android.messaging.util.Assert; import com.android.messaging.util.Assert.DoesNotRunOnMainThread; +import com.android.messaging.util.ImageUtils; import java.util.Arrays; import java.util.List; @@ -41,10 +41,20 @@ import java.util.List; */ public class EncodedImageResource extends ImageResource { private final byte[] mImageBytes; + private final int mDesiredWidth; + private final int mDesiredHeight; public EncodedImageResource(String key, byte[] imageBytes, int orientation) { + this(key, imageBytes, orientation, ImageRequest.UNSPECIFIED_SIZE, + ImageRequest.UNSPECIFIED_SIZE); + } + + public EncodedImageResource(String key, byte[] imageBytes, int orientation, + final int desiredWidth, final int desiredHeight) { super(key, orientation); mImageBytes = imageBytes; + mDesiredWidth = desiredWidth; + mDesiredHeight = desiredHeight; } @Override @@ -54,7 +64,7 @@ public class EncodedImageResource extends ImageResource { try { // This should only be called during the decode request. Assert.isNotMainThread(); - return BitmapFactory.decodeByteArray(mImageBytes, 0, mImageBytes.length); + return decodeSampledBitmap(); } finally { releaseLock(); } @@ -99,11 +109,15 @@ public class EncodedImageResource extends ImageResource { return true; } + private Bitmap decodeSampledBitmap() { + return ImageUtils.decodeByteArraySampled(mImageBytes, mDesiredWidth, mDesiredHeight); + } + @Override MediaRequest getMediaDecodingRequest( final MediaRequest originalRequest) { Assert.isTrue(isEncoded()); - return new DecodeImageRequest(); + return new DecodeImageRequest(originalRequest); } /** @@ -112,7 +126,22 @@ public class EncodedImageResource extends ImageResource { * properties such as binding. */ private class DecodeImageRequest implements MediaRequest { - public DecodeImageRequest() { + private final int mRequestDesiredWidth; + private final int mRequestDesiredHeight; + + public DecodeImageRequest( + final MediaRequest originalRequest) { + int desiredWidth = mDesiredWidth; + int desiredHeight = mDesiredHeight; + if (originalRequest != null) { + final MediaRequestDescriptor descriptor = originalRequest.getDescriptor(); + if (descriptor instanceof ImageRequestDescriptor) { + desiredWidth = ((ImageRequestDescriptor) descriptor).desiredWidth; + desiredHeight = ((ImageRequestDescriptor) descriptor).desiredHeight; + } + } + mRequestDesiredWidth = desiredWidth; + mRequestDesiredHeight = desiredHeight; // Hold a ref onto the encoded resource before the request finishes. addRef(); } @@ -129,8 +158,11 @@ public class EncodedImageResource extends ImageResource { Assert.isNotMainThread(); acquireLock(); try { - final Bitmap decodedBitmap = BitmapFactory.decodeByteArray(mImageBytes, 0, - mImageBytes.length); + final Bitmap decodedBitmap = ImageUtils.decodeByteArraySampled(mImageBytes, + mRequestDesiredWidth, mRequestDesiredHeight); + if (decodedBitmap == null) { + throw new RuntimeException("failed decoding encoded bitmap"); + } return new DecodedImageResource(getKey(), decodedBitmap, getOrientation()); } finally { releaseLock(); diff --git a/app/src/main/java/com/android/messaging/datamodel/media/NetworkUriImageRequest.java b/app/src/main/java/com/android/messaging/datamodel/media/NetworkUriImageRequest.java index ff7d800..c7faf82 100644 --- a/app/src/main/java/com/android/messaging/datamodel/media/NetworkUriImageRequest.java +++ b/app/src/main/java/com/android/messaging/datamodel/media/NetworkUriImageRequest.java @@ -18,11 +18,11 @@ package com.android.messaging.datamodel.media; import android.content.Context; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.support.v7.mms.pdu.ContentType; import com.android.messaging.Factory; import com.android.messaging.util.Assert; +import com.android.messaging.util.ImageUtils; import com.android.messaging.util.LogUtil; import java.io.FileNotFoundException; @@ -91,7 +91,11 @@ public class NetworkUriImageRequest extends connection.setDoInput(true); connection.connect(); if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { - bitmap = BitmapFactory.decodeStream(connection.getInputStream()); + try (InputStream inputStream = connection.getInputStream()) { + final byte[] bytes = ImageUtils.readStreamToByteArray(inputStream); + bitmap = ImageUtils.decodeByteArraySampled(bytes, + mDescriptor.desiredWidth, mDescriptor.desiredHeight); + } } } catch (MalformedURLException e) { LogUtil.e(LogUtil.BUGLE_TAG, diff --git a/app/src/main/java/com/android/messaging/ui/conversationlist/ConversationListActivity.java b/app/src/main/java/com/android/messaging/ui/conversationlist/ConversationListActivity.java index 51e446b..a9efd65 100644 --- a/app/src/main/java/com/android/messaging/ui/conversationlist/ConversationListActivity.java +++ b/app/src/main/java/com/android/messaging/ui/conversationlist/ConversationListActivity.java @@ -19,6 +19,7 @@ package com.android.messaging.ui.conversationlist; import android.os.Bundle; import android.view.ActionMode; +import android.window.SplashScreenView; import android.view.Menu; import android.view.MenuItem; import androidx.annotation.NonNull; @@ -34,6 +35,7 @@ public class ConversationListActivity extends AbstractConversationListActivity { @Override protected void onCreate(final Bundle savedInstanceState) { Trace.beginSection("ConversationListActivity.onCreate"); + getSplashScreen().setOnExitAnimationListener(SplashScreenView::remove); setTheme(R.style.BugleTheme_ConversationListActivity); super.onCreate(savedInstanceState); mConversationListFragment = ConversationListFragment.createConversationListFragment(null); diff --git a/app/src/main/java/com/android/messaging/ui/conversationlist/ConversationListItemView.java b/app/src/main/java/com/android/messaging/ui/conversationlist/ConversationListItemView.java index d7bc8df..4f92458 100644 --- a/app/src/main/java/com/android/messaging/ui/conversationlist/ConversationListItemView.java +++ b/app/src/main/java/com/android/messaging/ui/conversationlist/ConversationListItemView.java @@ -20,10 +20,12 @@ import android.content.Context; import android.content.res.Resources; import android.database.Cursor; import android.graphics.Color; +import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Typeface; import android.net.Uri; import android.support.v7.mms.pdu.ContentType; +import android.text.Layout; import android.text.SpannableString; import android.text.Spanned; import android.text.StaticLayout; @@ -221,6 +223,9 @@ public class ConversationListItemView extends FrameLayout implements OnClickList mListDividerView = findViewById(R.id.conversation_list_divider); mConversationNameView.addOnLayoutChangeListener(this); mSnippetTextView.addOnLayoutChangeListener(this); + if (mCategoryChipView != null) { + mCategoryChipView.addOnLayoutChangeListener(this); + } final Resources resources = getContext().getResources(); final Resources.Theme theme = getContext().getTheme(); @@ -243,6 +248,8 @@ public class ConversationListItemView extends FrameLayout implements OnClickList setSnippet(); } else if (v == mSubjectTextView) { setSubject(); + } else if (v == mCategoryChipView) { + alignSimBadgeToFirstSnippetLine(); } } @@ -258,10 +265,12 @@ public class ConversationListItemView extends FrameLayout implements OnClickList if (!SimNameUtil.shouldShowSimName(getContext())) { mCategoryChipView.setText(null); mCategoryChipView.setVisibility(GONE); + mCategoryChipView.setTranslationY(0f); return; } mCategoryChipView.setText(SimNameUtil.getSimDisplayName(getContext(), mData.getSelfId())); mCategoryChipView.setVisibility(VISIBLE); + alignSimBadgeToFirstSnippetLine(); } private void setConversationName() { @@ -344,12 +353,41 @@ public class ConversationListItemView extends FrameLayout implements OnClickList final int indent = getSnippetChipIndent(); if (indent <= 0) { mSnippetTextView.setText(snippetText); + } else { + final SpannableString spanned = new SpannableString(snippetText == null ? "" : snippetText); + spanned.setSpan(new LeadingMarginSpan.Standard(indent, 0), + 0, spanned.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + mSnippetTextView.setText(spanned); + } + alignSimBadgeToFirstSnippetLine(); + } + + private void alignSimBadgeToFirstSnippetLine() { + if (mCategoryChipView == null) { return; } - final SpannableString spanned = new SpannableString(snippetText == null ? "" : snippetText); - spanned.setSpan(new LeadingMarginSpan.Standard(indent, 0), - 0, spanned.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - mSnippetTextView.setText(spanned); + if (mCategoryChipView.getVisibility() != VISIBLE || mSnippetTextView == null) { + mCategoryChipView.setTranslationY(0f); + return; + } + int chipHeight = mCategoryChipView.getHeight(); + if (chipHeight <= 0) { + mCategoryChipView.measure( + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); + chipHeight = mCategoryChipView.getMeasuredHeight(); + } + if (chipHeight <= 0) { + return; + } + final Paint.FontMetricsInt fm = mSnippetTextView.getPaint().getFontMetricsInt(); + final int textHeight = fm.descent - fm.ascent; + int textTop = mSnippetTextView.getPaddingTop(); + final Layout layout = mSnippetTextView.getLayout(); + if (layout != null && layout.getLineCount() > 0) { + textTop = mSnippetTextView.getPaddingTop() + layout.getLineBaseline(0) + fm.ascent; + } + mCategoryChipView.setTranslationY(textTop + (textHeight - chipHeight) / 2f); } private int getSnippetChipIndent() { diff --git a/app/src/main/java/com/android/messaging/ui/home/HomeCategoryAddModal.java b/app/src/main/java/com/android/messaging/ui/home/HomeCategoryAddModal.java index 014367a..5435221 100644 --- a/app/src/main/java/com/android/messaging/ui/home/HomeCategoryAddModal.java +++ b/app/src/main/java/com/android/messaging/ui/home/HomeCategoryAddModal.java @@ -22,14 +22,20 @@ public final class HomeCategoryAddModal { void onCategoryCreated(HomeCategoryStore.Category created); } + private static boolean sShowing; + private HomeCategoryAddModal() { } public static void show(@NonNull final Context context, @Nullable final Listener listener) { + if (sShowing) { + return; + } + sShowing = true; final View content = LayoutInflater.from(context) .inflate(R.layout.home_category_name_dialog, null, false); final EditText field = content.findViewById(R.id.home_category_name_field); - HomeModal.builder(context) + final HomeModal.Handle handle = HomeModal.builder(context) .icon(R.drawable.ic_home_category) .title(R.string.home_category_add) .message(R.string.home_category_name_message) @@ -44,6 +50,11 @@ public final class HomeCategoryAddModal { } }) .show(); + if (handle == null || handle.dialog == null) { + sShowing = false; + return; + } + handle.dialog.setOnDismissListener(dialog -> sShowing = false); if (field != null) { field.requestFocus(); ImeUtil.get().showImeKeyboard(context, field); diff --git a/app/src/main/java/com/android/messaging/util/ImageUtils.java b/app/src/main/java/com/android/messaging/util/ImageUtils.java index 278bad9..51e1864 100644 --- a/app/src/main/java/com/android/messaging/util/ImageUtils.java +++ b/app/src/main/java/com/android/messaging/util/ImageUtils.java @@ -202,6 +202,46 @@ public class ImageUtils { return inSampleSize; } + /** + * Cap for full-resolution decodes when the caller did not give a target size. + * 2048px keeps a 12 MP photo from becoming a ~48 MB ARGB_8888 bitmap. + */ + public static final int MAX_DECODE_EDGE = 2048; + + public static Bitmap decodeByteArraySampled(final byte[] bytes, final int reqWidth, + final int reqHeight) { + if (bytes == null || bytes.length == 0) { + return null; + } + final BitmapFactory.Options bounds = new BitmapFactory.Options(); + bounds.inJustDecodeBounds = true; + BitmapFactory.decodeByteArray(bytes, 0, bytes.length, bounds); + int targetWidth = reqWidth; + int targetHeight = reqHeight; + if (targetWidth == ImageRequest.UNSPECIFIED_SIZE + && targetHeight == ImageRequest.UNSPECIFIED_SIZE) { + targetWidth = MAX_DECODE_EDGE; + targetHeight = MAX_DECODE_EDGE; + } + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.outWidth = bounds.outWidth; + options.outHeight = bounds.outHeight; + options.inSampleSize = get().calculateInSampleSize(options, targetWidth, targetHeight); + options.inJustDecodeBounds = false; + options.inMutable = true; + return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); + } + + public static byte[] readStreamToByteArray(final InputStream inputStream) throws IOException { + final ByteArrayOutputStream output = new ByteArrayOutputStream(); + final byte[] buffer = new byte[16 * 1024]; + int read; + while ((read = inputStream.read(buffer)) != -1) { + output.write(buffer, 0, read); + } + return output.toByteArray(); + } + private static final String[] MEDIA_CONTENT_PROJECTION = new String[] { MediaStore.MediaColumns.MIME_TYPE }; diff --git a/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..425d79735af5ad8476a6757fdc533549a202dc4d GIT binary patch literal 10744 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index fb36b7e..9b579af 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,18 +1,21 @@ - - - + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index d0dcbf4..0000000 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_monochrome.xml b/app/src/main/res/drawable/ic_launcher_monochrome.xml index 9cf5e2c..aceadf9 100644 --- a/app/src/main/res/drawable/ic_launcher_monochrome.xml +++ b/app/src/main/res/drawable/ic_launcher_monochrome.xml @@ -1,19 +1,4 @@ - - - - - + diff --git a/app/src/main/res/layout/conversation_list_fragment.xml b/app/src/main/res/layout/conversation_list_fragment.xml index e3be160..e596bd4 100644 --- a/app/src/main/res/layout/conversation_list_fragment.xml +++ b/app/src/main/res/layout/conversation_list_fragment.xml @@ -275,8 +275,8 @@ + android:layout_width="24dp" + android:layout_height="24dp" /> diff --git a/app/src/main/res/layout/home_category_add_tab.xml b/app/src/main/res/layout/home_category_add_tab.xml index c999ed6..0acf76b 100644 --- a/app/src/main/res/layout/home_category_add_tab.xml +++ b/app/src/main/res/layout/home_category_add_tab.xml @@ -2,9 +2,12 @@ diff --git a/proguard-release.flags b/proguard-release.flags index 67ae150..36b6720 100644 --- a/proguard-release.flags +++ b/proguard-release.flags @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. --keep class com.android.messaging.ui.contact.* { *; } - -assumenosideeffects public class com.android.messaging.util.Trace { public void beginSection(...); public void endSection(...); diff --git a/proguard.flags b/proguard.flags index f7b3dbc..e35b925 100644 --- a/proguard.flags +++ b/proguard.flags @@ -22,54 +22,45 @@ RuntimeVisibleTypeAnnotations, AnnotationDefault --keep class com.android.messaging.* { *; } --keep class com.android.messaging.*.* { *; } --keep class com.android.messaging.*.*.* { *; } - -# TODO(b/373579455): Evaluate if needs to be kept. +# Manifest / XML entry points. Do not keep the whole app or androidx packages — +# Play requires 25% shrink / optimize / obfuscate when uncompressed DEX > 10 MB. -keep public class * extends android.app.Activity { void (); } -# TODO(b/373579455): Evaluate if needs to be kept. -keep public class * extends android.app.Application { void (); } -# TODO(b/373579455): Evaluate if needs to be kept. -keep public class * extends android.app.Service { void (); } -# TODO(b/373579455): Evaluate if needs to be kept. -keep public class * extends android.content.BroadcastReceiver { void (); } -# TODO(b/373579455): Evaluate if needs to be kept. -keep public class * extends android.content.ContentProvider { void (); } -# TODO(b/373579455): Evaluate if needs to be kept. -keep public class * extends android.app.backup.BackupAgentHelper { void (); } -# TODO(b/373579455): Evaluate if needs to be kept. -keep public class * extends android.preference.Preference { void (); } -# TODO(b/373579455): Evaluate if needs to be kept. +-keep public class * extends androidx.preference.Preference { + public (android.content.Context, android.util.AttributeSet); + public (android.content.Context, android.util.AttributeSet, int); +} -keep public class * extends androidx.fragment.app.Fragment { void (); } --keep public class com.android.vcard.* { *; } --keep class androidx.collection.* { *; } --keep class androidx.core.* { *; } --keep class androidx.core.*.* { *; } --keep class androidx.appcompat.* { *; } --keep class androidx.appcompat.*.* { *; } --keep class androidx.recyclerview.widget.* { *; } --keep class androidx.viewpager.widget.* { *; } - -# Keep rastermill classes that need to be accessed from native code (JNI) --keep class android.support.rastermill.** { *; } +# Actions cross the ActionService / BackgroundWorker via Parcelable extras. +-keep class com.android.messaging.datamodel.action.Action { + void (); +} +-keep class * extends com.android.messaging.datamodel.action.Action { + public static android.os.Parcelable$Creator CREATOR; + (...); +} # Preserve the name of the getCaller method so it can find itself in the stack trace it generates -keepclassmembers public class com.android.messaging.util.DebugUtils { @@ -77,7 +68,7 @@ } # Keep the static fields of referenced inner classes of auto-generated R classes, in case we -# access those fields by reflection (e.g. EmojiMarkup) +# access those fields by reflection -keepclassmembers class **.R$* { public static ; }