[
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "## Expected Behavior\n\n\n## Actual Behavior\n\n\n## Steps to Reproduce the Problem\n\n1.\n1.\n1.\n\n## Specifications\n\n- Version:\n- Platform:"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "Fixes #<issue_number_goes_here>\n\n> It's a good idea to open an issue first for discussion.\n\n- [ ] Tests pass\n- [ ] Appropriate changes to README are included in PR"
  },
  {
    "path": ".github/workflows/android.yml",
    "content": "name: Android CI\n\non: [push]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: Check out repository\n      uses: actions/checkout@v3\n      with:\n        submodules: true\n    - name: Set up JDK 11\n      uses: actions/setup-java@v2\n      with:\n        distribution: 'adopt'\n        java-version: '11'\n    - name: Build with Gradle\n      run: ./gradlew assembleDebug lintVitalRelease\n"
  },
  {
    "path": ".gitignore",
    "content": "/.gradle/\n/.idea/\n/build/\n/captures/\n/local.properties\n.DS_Store\n*.iml\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"appiconloader-iconloaderlib/systemui\"]\n\tpath = appiconloader-iconloaderlib/systemui\n\turl = https://android.googlesource.com/platform/frameworks/libs/systemui\n"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "PRIVACY.md",
    "content": "# Privacy Policy\n\nHai Zhang built the AppIconLoader Sample app as an Open Source app. This SERVICE is provided by Hai Zhang at no cost and is intended for use as is.\n\nThis Service does not collect, use, or share your Personal Information.\n\nIf you have any questions or suggestions about my Privacy Policy, do not hesitate to contact me at https://github.com/zhanghai/AppIconLoader.\n"
  },
  {
    "path": "README.md",
    "content": "# AppIconLoader\n\n[![Android CI status](https://github.com/zhanghai/AppIconLoader/workflows/Android%20CI/badge.svg)](https://github.com/zhanghai/AppIconLoader/actions) [![GitHub release](https://img.shields.io/github/v/release/zhanghai/AppIconLoader)](https://github.com/zhanghai/AppIconLoader/releases) [![License](https://img.shields.io/github/license/zhanghai/AppIconLoader?color=blue)](LICENSE)\n\nAndroid app icon loader from AOSP [iconloaderlib](https://android.googlesource.com/platform/frameworks/libs/systemui/+/refs/heads/master/iconloaderlib/), with optional Glide and Coil integration.\n\nThis is not an officially supported Google product.\n\n## Why AppIconLoader?\n\nBecause [`PackageManager.getApplicationIcon()`](https://developer.android.com/reference/android/content/pm/PackageManager#getApplicationIcon(android.content.pm.ApplicationInfo)) (or [`PackageItemInfo.loadIcon()`](https://developer.android.com/reference/android/content/pm/PackageItemInfo#loadIcon(android.content.pm.PackageManager))) just doesn't work well with [adaptive icons](https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive). Non-adaptive icons usually have some shadow baked in (it's the recommended behavior), however adaptive icons never contain a shadow themselves, so we'll need to manually add the shadow or icons with a white background will just blend into our app's own background.\n\nThis library packaged the AOSP iconloaderlib for loading app icons, which has proper shadow and badging logic, and added easy integration with Glide and Coil.\n\nMeanwhile, by passing `true` for the `shrinkNonAdaptiveIcons` parameter, this library can also synthesize adaptive icons for apps that don't have it.\n\n## Preview\n\n<a href=\"https://play.google.com/store/apps/details?id=me.zhanghai.android.appiconloader.sample\" target=\"_blank\"><img alt=\"Google Play\" height=\"90\" src=\"https://play.google.com/intl/en_US/badges/images/generic/en_badge_web_generic.png\"/></a>\n\n[Sample APK](https://github.com/zhanghai/AppIconLoader/releases/latest/download/sample-release.apk)\n\n<img src=\"fastlane/metadata/android/en-US/images/phoneScreenshots/2.png\" width=\"49%\" />\n\n## Integration\n\nGradle:\n\n```gradle\n// For using with Glide.\nimplementation 'me.zhanghai.android.appiconloader:appiconloader-glide:1.5.0'\n// For using with Coil.\nimplementation 'me.zhanghai.android.appiconloader:appiconloader-coil:1.5.0'\n// For using AppIconLoader directly.\nimplementation 'me.zhanghai.android.appiconloader:appiconloader:1.5.0'\n// For using iconloaderlib directly.\nimplementation 'me.zhanghai.android.appiconloader:appiconloader-iconloaderlib:1.5.0'\n```\n\n## Usage\n\n### Glide integration\n\nSee [Glide's documentation on registering a `ModuleLoader`](https://bumptech.github.io/glide/tut/custom-modelloader.html#registering-our-modelloader-with-glide).\n\nInside your implementation of `AppGlideModule.registerComponents()`, you can have something like the following code fragment:\n\n```java\nint iconSize = context.getResources().getDimensionPixelSize(R.dimen.app_icon_size);\nregistry.prepend(PackageInfo.class, Bitmap.class, new AppIconModelLoader.Factory(iconSize,\n        false, context));\n```\n\nSee also the sample app's [`AppGlideModule` implementation](sample/src/main/java/me/zhanghai/android/appiconloader/sample/AppGlideModule.java).\n\nAfter the setup above, Glide will support loading app icons with the app's `PackageInfo`.\n\n```java\nGlideApp.with(imageView)\n        .load(packageInfo)\n        .into(imageView);\n```\n\n### Coil integration\n\n```kotlin\nval iconSize = context.resources.getDimensionPixelSize(R.dimen.app_icon_size)\nCoil.setImageLoader(\n    ImageLoader.Builder(context)\n        .components {\n            add(AppIconKeyer())\n            add(AppIconFetcher.Factory(iconSize, false, context))\n        }\n        .build()\n)\n```\n\nAfter the setup above, Coil will support loading app icons with the app's `PackageInfo`.\n\n```kotlin\nimageView.loadAny(packageInfo)\n```\n\n### AppIconLoader\n\n[`AppIconLoader`](appiconloader/src/main/java/me/zhanghai/android/appiconloader/AppIconLoader.java) is the API exposed by this library, and you can simply call `AppIconLoader.loadIcon()` to load an app icon. You can also use `AppIconLoader.getIconKey()` to generate a cache key for your loaded icon.\n\n### iconloaderlib\n\nPlease refer to [its source code](https://android.googlesource.com/platform/frameworks/libs/systemui/+/refs/heads/master/iconloaderlib/).\n\n## License\n\n    Copyright 2020 Google LLC\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n        http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n"
  },
  {
    "path": "appiconloader/.gitignore",
    "content": "/.externalNativeBuild/\n/build/\n/out/\n"
  },
  {
    "path": "appiconloader/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 33\n    buildToolsVersion '33.0.0'\n    defaultConfig {\n        minSdkVersion 21\n        targetSdkVersion 33\n        versionCode Integer.parseInt(VERSION_CODE)\n        versionName VERSION_NAME\n        consumerProguardFiles 'proguard-rules.pro'\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n        }\n    }\n}\n\ndependencies {\n    implementation 'androidx.annotation:annotation:1.4.0'\n    implementation project(':appiconloader-iconloaderlib')\n}\n\napply plugin: 'com.vanniktech.maven.publish'\n"
  },
  {
    "path": "appiconloader/gradle.properties",
    "content": "POM_NAME=AppIconLoader\n"
  },
  {
    "path": "appiconloader/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "appiconloader/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<manifest package=\"me.zhanghai.android.appiconloader\" />\n"
  },
  {
    "path": "appiconloader/src/main/java/me/zhanghai/android/appiconloader/AppIconLoader.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.graphics.Bitmap;\nimport android.graphics.drawable.Drawable;\nimport android.os.UserHandle;\n\nimport java.util.concurrent.ConcurrentLinkedQueue;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.Px;\nimport me.zhanghai.android.appiconloader.iconloaderlib.BaseIconFactory;\nimport me.zhanghai.android.appiconloader.iconloaderlib.BitmapInfo;\n\npublic class AppIconLoader {\n    @Px\n    private final int mIconSize;\n    private final boolean mShrinkNonAdaptiveIcons;\n    @NonNull\n    private final Context mContext;\n\n    @NonNull\n    private final ConcurrentLinkedQueue<IconFactory> mIconFactoryPool =\n            new ConcurrentLinkedQueue<>();\n\n    public AppIconLoader(@Px int iconSize, boolean shrinkNonAdaptiveIcons,\n                         @NonNull Context context) {\n        mIconSize = iconSize;\n        mShrinkNonAdaptiveIcons = shrinkNonAdaptiveIcons;\n        mContext = context;\n    }\n\n    @NonNull\n    public static String getIconKey(@NonNull ApplicationInfo applicationInfo, long versionCode,\n                                    @NonNull Context context) {\n        UserHandle user = UserHandleCompat.getUserHandleForUid(applicationInfo.uid);\n        return applicationInfo.packageName + \":\" + versionCode + \":\"\n                + UserSerialNumberCache.getSerialNumber(user, context);\n    }\n\n    @NonNull\n    public static String getIconKey(@NonNull PackageInfo packageInfo, @NonNull Context context) {\n        return getIconKey(packageInfo.applicationInfo, PackageInfoCompat.getLongVersionCode(\n                packageInfo), context);\n    }\n\n    @NonNull\n    public Bitmap loadIcon(@NonNull ApplicationInfo applicationInfo, boolean isInstantApp) {\n        Drawable unbadgedIcon = PackageItemInfoCompat.loadUnbadgedIcon(applicationInfo,\n                mContext.getPackageManager());\n        UserHandle user = UserHandleCompat.getUserHandleForUid(applicationInfo.uid);\n        IconFactory iconFactory = mIconFactoryPool.poll();\n        if (iconFactory == null) {\n            iconFactory = new IconFactory(mIconSize, mContext);\n        }\n        try {\n            return iconFactory.createBadgedIconBitmap(unbadgedIcon, user, mShrinkNonAdaptiveIcons,\n                    isInstantApp).icon;\n        } finally {\n            mIconFactoryPool.offer(iconFactory);\n        }\n    }\n\n    @NonNull\n    public Bitmap loadIcon(@NonNull ApplicationInfo applicationInfo) {\n        return loadIcon(applicationInfo, false);\n    }\n\n    private static class IconFactory extends BaseIconFactory {\n        private final float[] mTempScale = new float[1];\n\n        public IconFactory(@Px int iconBitmapSize, @NonNull Context context) {\n            super(context, context.getResources().getConfiguration().densityDpi, iconBitmapSize,\n                    true);\n\n            disableColorExtraction();\n        }\n\n        @NonNull\n        public BitmapInfo createBadgedIconBitmap(@NonNull Drawable icon, @Nullable UserHandle user,\n                                                 boolean shrinkNonAdaptiveIcons,\n                                                 boolean isInstantApp) {\n            return super.createBadgedIconBitmap(icon, user, shrinkNonAdaptiveIcons, isInstantApp,\n                    mTempScale);\n        }\n    }\n}\n"
  },
  {
    "path": "appiconloader/src/main/java/me/zhanghai/android/appiconloader/PackageInfoCompat.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader;\n\nimport android.content.pm.PackageInfo;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\n\nclass PackageInfoCompat {\n    private PackageInfoCompat() {}\n\n    public static long getLongVersionCode(@NonNull PackageInfo info) {\n        if (Build.VERSION.SDK_INT >= 28) {\n            return info.getLongVersionCode();\n        } else {\n            //noinspection deprecation\n            return info.versionCode;\n        }\n    }\n}\n"
  },
  {
    "path": "appiconloader/src/main/java/me/zhanghai/android/appiconloader/PackageItemInfoCompat.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader;\n\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.ComponentInfo;\nimport android.content.pm.PackageItemInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.drawable.Drawable;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nclass PackageItemInfoCompat {\n    private PackageItemInfoCompat() {}\n\n    public static Drawable loadUnbadgedIcon(@NonNull PackageItemInfo packageItemInfo,\n                                            @NonNull PackageManager packageManager) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {\n            return packageItemInfo.loadUnbadgedIcon(packageManager);\n        } else {\n            ApplicationInfo applicationInfo = getApplicationInfo(packageItemInfo);\n            Drawable drawable = null;\n            if (packageItemInfo.packageName != null) {\n                drawable = packageManager.getDrawable(packageItemInfo.packageName,\n                        packageItemInfo.icon, applicationInfo);\n            }\n            if (drawable == null && packageItemInfo != applicationInfo && applicationInfo != null) {\n                drawable = loadUnbadgedIcon(applicationInfo, packageManager);\n            }\n            if (drawable == null) {\n                drawable = loadDefaultIcon(packageItemInfo, packageManager);\n            }\n            return drawable;\n        }\n    }\n\n    @Nullable\n    private static ApplicationInfo getApplicationInfo(@NonNull PackageItemInfo packageItemInfo) {\n        if (packageItemInfo instanceof ApplicationInfo) {\n            return (ApplicationInfo) packageItemInfo;\n        } else if (packageItemInfo instanceof ComponentInfo) {\n            return ((ComponentInfo) packageItemInfo).applicationInfo;\n        } else {\n            return null;\n        }\n    }\n\n    @NonNull\n    private static Drawable loadDefaultIcon(@NonNull PackageItemInfo packageItemInfo,\n                                            @NonNull PackageManager packageManager) {\n        return packageManager.getDefaultActivityIcon();\n    }\n}\n"
  },
  {
    "path": "appiconloader/src/main/java/me/zhanghai/android/appiconloader/UserHandleCompat.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader;\n\nimport android.os.Build;\nimport android.os.UserHandle;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.InvocationTargetException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nclass UserHandleCompat {\n    private static final int PER_USER_RANGE = 100000;\n    private static final int USER_SYSTEM = 0;\n    private static final boolean MU_ENABLED = true;\n\n    @Nullable\n    private static Constructor<UserHandle> sConstructor;\n    @NonNull\n    private static final Object sConstructorLock = new Object();\n\n    private UserHandleCompat() {}\n\n    @NonNull\n    public static UserHandle getUserHandleForUid(int uid) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            return UserHandle.getUserHandleForUid(uid);\n        } else {\n            int userId = getUserId(uid);\n            Constructor<UserHandle> constructor = getConstructor();\n            try {\n                return constructor.newInstance(userId);\n            } catch (IllegalAccessException | InstantiationException\n                    | InvocationTargetException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    private static int getUserId(int uid) {\n        if (MU_ENABLED) {\n            return uid / PER_USER_RANGE;\n        } else {\n            return USER_SYSTEM;\n        }\n    }\n\n    @NonNull\n    private static Constructor<UserHandle> getConstructor() {\n        synchronized (sConstructorLock) {\n            if (sConstructor == null) {\n                try {\n                    sConstructor = UserHandle.class.getDeclaredConstructor(int.class);\n                } catch (NoSuchMethodException e) {\n                    throw new RuntimeException(e);\n                }\n            }\n            return sConstructor;\n        }\n    }\n}\n"
  },
  {
    "path": "appiconloader/src/main/java/me/zhanghai/android/appiconloader/UserSerialNumberCache.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader;\n\nimport android.content.Context;\nimport android.os.UserHandle;\nimport android.os.UserManager;\nimport android.util.ArrayMap;\n\nimport androidx.annotation.NonNull;\n\nclass UserSerialNumberCache {\n    private static final long CACHE_MILLIS = 1000;\n\n    @NonNull\n    private static final ArrayMap<UserHandle, long[]> sCache = new ArrayMap<>();\n\n    UserSerialNumberCache() {}\n\n    public static long getSerialNumber(@NonNull UserHandle user, @NonNull Context context) {\n        synchronized (sCache) {\n            long[] serialNumberAndTime = sCache.get(user);\n            if (serialNumberAndTime == null) {\n                serialNumberAndTime = new long[2];\n                sCache.put(user, serialNumberAndTime);\n            }\n            long time = System.currentTimeMillis();\n            if (serialNumberAndTime[1] + CACHE_MILLIS <= time) {\n                UserManager userManager = (UserManager) context.getSystemService(\n                        Context.USER_SERVICE);\n                serialNumberAndTime[0] = userManager.getSerialNumberForUser(user);\n                serialNumberAndTime[1] = time;\n            }\n            return serialNumberAndTime[0];\n        }\n    }\n}\n"
  },
  {
    "path": "appiconloader-coil/.gitignore",
    "content": "/.externalNativeBuild/\n/build/\n/out/\n"
  },
  {
    "path": "appiconloader-coil/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 33\n    buildToolsVersion '33.0.0'\n    defaultConfig {\n        minSdkVersion 21\n        targetSdkVersion 33\n        versionCode Integer.parseInt(VERSION_CODE)\n        versionName VERSION_NAME\n        consumerProguardFiles 'proguard-rules.pro'\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n        }\n    }\n}\n\ndependencies {\n    implementation 'androidx.annotation:annotation:1.4.0'\n    implementation 'io.coil-kt:coil-base:2.2.0'\n    implementation project(':appiconloader')\n}\n\napply plugin: 'com.vanniktech.maven.publish'\n"
  },
  {
    "path": "appiconloader-coil/gradle.properties",
    "content": "POM_NAME=AppIconLoader Coil\n"
  },
  {
    "path": "appiconloader-coil/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "appiconloader-coil/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<manifest package=\"me.zhanghai.android.appiconloader.coil\" />\n"
  },
  {
    "path": "appiconloader-coil/src/main/java/me/zhanghai/android/appiconloader/coil/AppIconFetcher.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.coil;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.graphics.Bitmap;\nimport android.graphics.drawable.BitmapDrawable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.Px;\nimport coil.ImageLoader;\nimport coil.decode.DataSource;\nimport coil.fetch.DrawableResult;\nimport coil.fetch.FetchResult;\nimport coil.fetch.Fetcher;\nimport coil.request.Options;\nimport kotlin.coroutines.Continuation;\nimport me.zhanghai.android.appiconloader.AppIconLoader;\n\npublic class AppIconFetcher implements Fetcher {\n    @NonNull\n    private final Options mOptions;\n    @NonNull\n    private final AppIconLoader mLoader;\n    @NonNull\n    private final ApplicationInfo mApplicationInfo;\n\n    public AppIconFetcher(@NonNull Options options, @NonNull AppIconLoader loader,\n                          @NonNull ApplicationInfo applicationInfo) {\n        mOptions = options;\n        mLoader = loader;\n        mApplicationInfo = applicationInfo;\n    }\n\n    @Nullable\n    @Override\n    public FetchResult fetch(@NonNull Continuation<? super FetchResult> continuation) {\n        Bitmap icon = mLoader.loadIcon(mApplicationInfo);\n        return new DrawableResult(new BitmapDrawable(mOptions.getContext().getResources(), icon),\n                true, DataSource.DISK);\n    }\n\n    public static class Factory implements Fetcher.Factory<PackageInfo> {\n        @NonNull\n        private final AppIconLoader mLoader;\n\n        public Factory(@Px int iconSize, boolean shrinkNonAdaptiveIcons, @NonNull Context context) {\n            context = context.getApplicationContext();\n            mLoader = new AppIconLoader(iconSize, shrinkNonAdaptiveIcons, context);\n        }\n\n        @Nullable\n        @Override\n        public Fetcher create(@NonNull PackageInfo packageInfo, @NonNull Options options,\n                              @NonNull ImageLoader imageLoader) {\n            return new AppIconFetcher(options, mLoader, packageInfo.applicationInfo);\n        }\n    }\n}\n"
  },
  {
    "path": "appiconloader-coil/src/main/java/me/zhanghai/android/appiconloader/coil/AppIconKeyer.java",
    "content": "package me.zhanghai.android.appiconloader.coil;\n\nimport android.content.pm.PackageInfo;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport coil.key.Keyer;\nimport coil.request.Options;\nimport me.zhanghai.android.appiconloader.AppIconLoader;\n\npublic class AppIconKeyer implements Keyer<PackageInfo> {\n    @Nullable\n    @Override\n    public String key(@NonNull PackageInfo packageInfo, @NonNull Options options) {\n        return AppIconLoader.getIconKey(packageInfo, options.getContext());\n    }\n}\n"
  },
  {
    "path": "appiconloader-glide/.gitignore",
    "content": "/.externalNativeBuild/\n/build/\n/out/\n"
  },
  {
    "path": "appiconloader-glide/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 33\n    buildToolsVersion '33.0.0'\n    defaultConfig {\n        minSdkVersion 21\n        targetSdkVersion 33\n        versionCode Integer.parseInt(VERSION_CODE)\n        versionName VERSION_NAME\n        consumerProguardFiles 'proguard-rules.pro'\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n        }\n    }\n}\n\ndependencies {\n    implementation 'androidx.annotation:annotation:1.4.0'\n    implementation 'com.github.bumptech.glide:glide:4.13.2'\n    implementation project(':appiconloader')\n}\n\napply plugin: 'com.vanniktech.maven.publish'\n"
  },
  {
    "path": "appiconloader-glide/gradle.properties",
    "content": "POM_NAME=AppIconLoader Glide\n"
  },
  {
    "path": "appiconloader-glide/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "appiconloader-glide/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<manifest package=\"me.zhanghai.android.appiconloader.glide\" />\n"
  },
  {
    "path": "appiconloader-glide/src/main/java/me/zhanghai/android/appiconloader/glide/AppIconModelLoader.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.glide;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.graphics.Bitmap;\n\nimport com.bumptech.glide.Priority;\nimport com.bumptech.glide.load.DataSource;\nimport com.bumptech.glide.load.Options;\nimport com.bumptech.glide.load.data.DataFetcher;\nimport com.bumptech.glide.load.model.ModelLoader;\nimport com.bumptech.glide.load.model.ModelLoaderFactory;\nimport com.bumptech.glide.load.model.MultiModelLoaderFactory;\nimport com.bumptech.glide.signature.ObjectKey;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.Px;\nimport me.zhanghai.android.appiconloader.AppIconLoader;\n\npublic class AppIconModelLoader implements ModelLoader<PackageInfo, Bitmap> {\n    @NonNull\n    private final AppIconLoader mLoader;\n    @NonNull\n    private final Context mContext;\n\n    private AppIconModelLoader(@Px int iconSize, boolean shrinkNonAdaptiveIcons,\n                               @NonNull Context context) {\n        mLoader = new AppIconLoader(iconSize, shrinkNonAdaptiveIcons, context);\n        mContext = context;\n    }\n\n    @Override\n    public boolean handles(@NonNull PackageInfo model) {\n        return true;\n    }\n\n    @Nullable\n    @Override\n    public LoadData<Bitmap> buildLoadData(@NonNull PackageInfo model, int width, int height,\n                                          @NonNull Options options) {\n        return new LoadData<>(new ObjectKey(AppIconLoader.getIconKey(model, mContext)), new Fetcher(\n                mLoader, model.applicationInfo));\n    }\n\n    private static class Fetcher implements DataFetcher<Bitmap> {\n        @NonNull\n        private final AppIconLoader mLoader;\n        @NonNull\n        private final ApplicationInfo mApplicationInfo;\n\n        public Fetcher(@NonNull AppIconLoader loader, @NonNull ApplicationInfo applicationInfo) {\n            mLoader = loader;\n            mApplicationInfo = applicationInfo;\n        }\n\n        @Override\n        public void loadData(@NonNull Priority priority,\n                             @NonNull DataCallback<? super Bitmap> callback) {\n            try {\n                Bitmap icon = mLoader.loadIcon(mApplicationInfo);\n                callback.onDataReady(icon);\n            } catch (Exception e) {\n                callback.onLoadFailed(e);\n            }\n        }\n\n        @Override\n        public void cleanup() {}\n\n        @Override\n        public void cancel() {}\n\n        @NonNull\n        @Override\n        public Class<Bitmap> getDataClass() {\n            return Bitmap.class;\n        }\n\n        @NonNull\n        @Override\n        public DataSource getDataSource() {\n            return DataSource.LOCAL;\n        }\n    }\n\n    public static class Factory implements ModelLoaderFactory<PackageInfo, Bitmap> {\n        @Px\n        private final int mIconSize;\n        private final boolean mShrinkNonAdaptiveIcons;\n        @NonNull\n        private final Context mContext;\n\n        public Factory(@Px int iconSize, boolean shrinkNonAdaptiveIcons, @NonNull Context context) {\n            mIconSize = iconSize;\n            mShrinkNonAdaptiveIcons = shrinkNonAdaptiveIcons;\n            mContext = context.getApplicationContext();\n        }\n\n        @NonNull\n        @Override\n        public ModelLoader<PackageInfo, Bitmap> build(\n                @NonNull MultiModelLoaderFactory multiFactory) {\n            return new AppIconModelLoader(mIconSize, mShrinkNonAdaptiveIcons, mContext);\n        }\n\n        @Override\n        public void teardown() {}\n    }\n}\n"
  },
  {
    "path": "appiconloader-iconloaderlib/.gitignore",
    "content": "/.externalNativeBuild/\n/build/\n/out/\n"
  },
  {
    "path": "appiconloader-iconloaderlib/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\napply from: 'generate-iconloaderlib-src.gradle'\n\nandroid {\n    compileSdkVersion 33\n    buildToolsVersion '33.0.0'\n    defaultConfig {\n        minSdkVersion 21\n        targetSdkVersion 33\n        versionCode Integer.parseInt(VERSION_CODE)\n        versionName VERSION_NAME\n        consumerProguardFiles 'proguard-rules.pro'\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n        }\n    }\n}\n\ndependencies {\n    implementation 'androidx.annotation:annotation:1.4.0'\n}\n\napply plugin: 'com.vanniktech.maven.publish'\n"
  },
  {
    "path": "appiconloader-iconloaderlib/generate-iconloaderlib-src.gradle",
    "content": "def aospIconloaderlibSrcDir = file('systemui/iconloaderlib')\ndef generatedIconloaderlibSrcDir = file(\"$buildDir/generated/iconloaderlib\")\n\ntask generateIconloaderlibSrc {\n    inputs.dir aospIconloaderlibSrcDir\n    outputs.dir generatedIconloaderlibSrcDir\n    doLast {\n        exec {\n            commandLine './generate-iconloaderlib-src.sh', aospIconloaderlibSrcDir,\n                    generatedIconloaderlibSrcDir\n        }\n    }\n}\n\npreBuild.dependsOn generateIconloaderlibSrc\n\nandroid {\n    sourceSets {\n        main {\n            java {\n                srcDirs += file(\"$generatedIconloaderlibSrcDir/java\")\n            }\n            res {\n                srcDirs += file(\"$generatedIconloaderlibSrcDir/res\")\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "appiconloader-iconloaderlib/generate-iconloaderlib-src.sh",
    "content": "#!/bin/bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nset -eu\n\nLAUNCHER3_CLASSES_ROOT=\"$1/src/com/android/launcher3/icons\"\nLAUNCHER3_RESOURCES_ROOT=\"$1/res\"\nLIBRARY_CLASSES_ROOT=\"$2/java/me/zhanghai/android/appiconloader/iconloaderlib\"\nLIBRARY_RESOURCES_ROOT=\"$2/res\"\nLIBRARY_CLASSES_FILES=(\n    \"BaseIconFactory.java\"\n    \"BitmapInfo.java\"\n    \"BitmapRenderer.java\"\n    \"ColorExtractor.java\"\n    \"FixedScaleDrawable.java\"\n    \"GraphicsUtils.java\"\n    \"IconNormalizer.java\"\n    \"ShadowGenerator.java\"\n)\nLIBRARY_RESOURCES_FILES=(\n    \"drawable/ic_instant_app_badge.xml\"\n    \"drawable-v26/adaptive_icon_drawable_wrapper.xml\"\n    \"values/colors.xml\"\n    \"values/dimens.xml\"\n)\n\nrm -rf \"${LIBRARY_CLASSES_ROOT}\"\nfor file in \"${LIBRARY_CLASSES_FILES[@]}\"; do\n    mkdir -p \"$(dirname \"${LIBRARY_CLASSES_ROOT}/${file}\")\"\n    cp \"${LAUNCHER3_CLASSES_ROOT}/${file}\" \"${LIBRARY_CLASSES_ROOT}/${file}\"\ndone\n\nfind \"${LIBRARY_CLASSES_ROOT}\" -iname '*.java' -type f -print0 | xargs -0 sed -Ei \\\n    -e 's/\\bcom\\.android\\.launcher3\\.icons\\b/me.zhanghai.android.appiconloader.iconloaderlib/g'\npatch -d \"${LIBRARY_CLASSES_ROOT}\" -p0 <iconloaderlib-classes.patch\n\nrm -rf \"${LIBRARY_RESOURCES_ROOT}\"\nfor file in \"${LIBRARY_RESOURCES_FILES[@]}\"; do\n    mkdir -p \"$(dirname \"${LIBRARY_RESOURCES_ROOT}/${file}\")\"\n    cp \"${LAUNCHER3_RESOURCES_ROOT}/${file}\" \"${LIBRARY_RESOURCES_ROOT}/${file}\"\ndone\n\nfind \"${LIBRARY_RESOURCES_ROOT}\" -iname '*.xml' -type f -print0 | xargs -0 sed -Ei \\\n    -e 's/\\bcom\\.android\\.launcher3\\.icons\\b/me.zhanghai.android.appiconloader.iconloaderlib/g'\npatch -d \"${LIBRARY_RESOURCES_ROOT}\" -p0 <iconloaderlib-resources.patch\n"
  },
  {
    "path": "appiconloader-iconloaderlib/gradle.properties",
    "content": "POM_NAME=AppIconLoader iconloaderlib\n"
  },
  {
    "path": "appiconloader-iconloaderlib/iconloaderlib-classes.patch",
    "content": "--- BaseIconFactory.java\n+++ BaseIconFactory.java\n@@ -25,6 +25,7 @@ import android.os.Build;\n import android.os.Process;\n import android.os.UserHandle;\n\n+import androidx.annotation.ChecksSdkIntAtLeast;\n import androidx.annotation.NonNull;\n\n import me.zhanghai.android.appiconloader.iconloaderlib.BitmapInfo.Extender;\n@@ -37,7 +38,9 @@ public class BaseIconFactory implements AutoCloseable {\n\n     private static final String TAG = \"BaseIconFactory\";\n     private static final int DEFAULT_WRAPPER_BACKGROUND = Color.WHITE;\n+    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.O)\n     static final boolean ATLEAST_OREO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;\n+    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.P)\n     static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;\n\n     private static final float ICON_BADGE_SCALE = 0.444f;\n@@ -361,12 +364,16 @@ public class BaseIconFactory implements AutoCloseable {\n         if (ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {\n             int offset = Math.max((int) Math.ceil(BLUR_FACTOR * size),\n                     Math.round(size * (1 - scale) / 2 ));\n-            icon.setBounds(offset, offset, size - offset, size - offset);\n+            // Work around bug in MIUI AdaptiveIconDrawableInjector.\n+            //icon.setBounds(offset, offset, size - offset, size - offset);\n+            icon.setBounds(0, 0, size - 2 * offset, size - 2 * offset);\n+            mCanvas.translate(offset, offset);\n             if (icon instanceof BitmapInfo.Extender) {\n                 ((Extender) icon).drawForPersistence(mCanvas);\n             } else {\n                 icon.draw(mCanvas);\n             }\n+            mCanvas.translate(-offset, -offset);\n         } else {\n             if (icon instanceof BitmapDrawable) {\n                 BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;\n--- BitmapInfo.java\n+++ BitmapInfo.java\n@@ -15,37 +15,16 @@\n  */\n package me.zhanghai.android.appiconloader.iconloaderlib;\n \n-import static me.zhanghai.android.appiconloader.iconloaderlib.GraphicsUtils.getExpectedBitmapSize;\n-\n import android.content.Context;\n import android.graphics.Bitmap;\n-import android.graphics.Bitmap.Config;\n-import android.graphics.BitmapFactory;\n import android.graphics.Canvas;\n import android.graphics.drawable.Drawable;\n-import android.os.Build;\n import android.os.UserHandle;\n-import android.util.Log;\n \n import androidx.annotation.NonNull;\n-import androidx.annotation.Nullable;\n-\n-import me.zhanghai.android.appiconloader.iconloaderlib.ThemedIconDrawable.ThemedBitmapInfo;\n-import me.zhanghai.android.appiconloader.iconloaderlib.cache.BaseIconCache;\n-\n-import java.io.ByteArrayOutputStream;\n-import java.io.IOException;\n \n public class BitmapInfo {\n \n-    public static final Bitmap LOW_RES_ICON = Bitmap.createBitmap(1, 1, Config.ALPHA_8);\n-    public static final BitmapInfo LOW_RES_INFO = fromBitmap(LOW_RES_ICON);\n-\n-    public static final String TAG = \"BitmapInfo\";\n-\n-    protected static final byte TYPE_DEFAULT = 1;\n-    protected static final byte TYPE_THEMED = 2;\n-\n     public final Bitmap icon;\n     public final int color;\n \n@@ -54,83 +33,6 @@ public class BitmapInfo {\n         this.color = color;\n     }\n \n-    /**\n-     * Ideally icon should not be null, except in cases when generating hardware bitmap failed\n-     */\n-    public final boolean isNullOrLowRes() {\n-        return icon == null || icon == LOW_RES_ICON;\n-    }\n-\n-    public final boolean isLowRes() {\n-        return LOW_RES_ICON == icon;\n-    }\n-\n-    /**\n-     * Returns a serialized version of BitmapInfo\n-     */\n-    @Nullable\n-    public byte[] toByteArray() {\n-        if (isNullOrLowRes()) {\n-            return null;\n-        }\n-        ByteArrayOutputStream out = new ByteArrayOutputStream(getExpectedBitmapSize(icon) + 1);\n-        try {\n-            out.write(TYPE_DEFAULT);\n-            icon.compress(Bitmap.CompressFormat.PNG, 100, out);\n-            out.flush();\n-            out.close();\n-            return out.toByteArray();\n-        } catch (IOException e) {\n-            Log.w(TAG, \"Could not write bitmap\");\n-            return null;\n-        }\n-    }\n-\n-    /**\n-     * Returns a new icon based on the theme of the context\n-     */\n-    public FastBitmapDrawable newThemedIcon(Context context) {\n-        return newIcon(context);\n-    }\n-\n-    /**\n-     * Creates a drawable for the provided BitmapInfo\n-     */\n-    public FastBitmapDrawable newIcon(Context context) {\n-        FastBitmapDrawable drawable = isLowRes()\n-                ? new PlaceHolderIconDrawable(this, context)\n-                : new FastBitmapDrawable(this);\n-        drawable.mDisabledAlpha = GraphicsUtils.getFloat(context, R.attr.disabledIconAlpha, 1f);\n-        return drawable;\n-    }\n-\n-    /**\n-     * Returns a BitmapInfo previously serialized using {@link #toByteArray()};\n-     */\n-    @NonNull\n-    public static BitmapInfo fromByteArray(byte[] data, int color, UserHandle user,\n-            BaseIconCache iconCache, Context context) {\n-        if (data == null) {\n-            return null;\n-        }\n-        BitmapFactory.Options decodeOptions;\n-        if (BitmapRenderer.USE_HARDWARE_BITMAP && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n-            decodeOptions = new BitmapFactory.Options();\n-            decodeOptions.inPreferredConfig = Bitmap.Config.HARDWARE;\n-        } else {\n-            decodeOptions = null;\n-        }\n-        if (data[0] == TYPE_DEFAULT) {\n-            return BitmapInfo.of(\n-                    BitmapFactory.decodeByteArray(data, 1, data.length - 1, decodeOptions),\n-                    color);\n-        } else if (data[0] == TYPE_THEMED) {\n-            return ThemedBitmapInfo.decode(data, color, decodeOptions, user, iconCache, context);\n-        } else {\n-            return null;\n-        }\n-    }\n-\n     public static BitmapInfo fromBitmap(@NonNull Bitmap bitmap) {\n         return of(bitmap, 0);\n     }\n--- BitmapRenderer.java\n+++ BitmapRenderer.java\n@@ -25,11 +25,14 @@ import android.graphics.RectF;\n import android.os.Build;\n import android.os.Build.VERSION_CODES;\n\n+import androidx.annotation.ChecksSdkIntAtLeast;\n+\n /**\n  * Interface representing a bitmap draw operation.\n  */\n public interface BitmapRenderer {\n\n+    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.P)\n     boolean USE_HARDWARE_BITMAP = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;\n\n     static Bitmap createSoftwareBitmap(int width, int height, BitmapRenderer renderer) {\n--- FixedScaleDrawable.java\n+++ FixedScaleDrawable.java\n@@ -5,13 +5,17 @@ import android.content.res.Resources.Theme;\n import android.graphics.Canvas;\n import android.graphics.drawable.ColorDrawable;\n import android.graphics.drawable.DrawableWrapper;\n+import android.os.Build;\n import android.util.AttributeSet;\n \n+import androidx.annotation.RequiresApi;\n+\n import org.xmlpull.v1.XmlPullParser;\n \n /**\n  * Extension of {@link DrawableWrapper} which scales the child drawables by a fixed amount.\n  */\n+@RequiresApi(Build.VERSION_CODES.O)\n public class FixedScaleDrawable extends DrawableWrapper {\n \n     // TODO b/33553066 use the constant defined in MaskableIconDrawable\n--- GraphicsUtils.java\n+++ GraphicsUtils.java\n@@ -15,23 +15,12 @@\n  */\n package me.zhanghai.android.appiconloader.iconloaderlib;\n\n-import android.content.Context;\n-import android.content.res.TypedArray;\n-import android.graphics.Bitmap;\n-import android.graphics.Color;\n-import android.graphics.Path;\n import android.graphics.Rect;\n import android.graphics.Region;\n import android.graphics.RegionIterator;\n-import android.graphics.drawable.AdaptiveIconDrawable;\n-import android.graphics.drawable.ColorDrawable;\n-import android.util.Log;\n\n import androidx.annotation.ColorInt;\n\n-import java.io.ByteArrayOutputStream;\n-import java.io.IOException;\n-\n public class GraphicsUtils {\n\n     private static final String TAG = \"GraphicsUtils\";\n@@ -53,30 +42,6 @@ public class GraphicsUtils {\n         return (color & 0x00ffffff) | (alpha << 24);\n     }\n\n-    /**\n-     * Compresses the bitmap to a byte array for serialization.\n-     */\n-    public static byte[] flattenBitmap(Bitmap bitmap) {\n-        ByteArrayOutputStream out = new ByteArrayOutputStream(getExpectedBitmapSize(bitmap));\n-        try {\n-            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);\n-            out.flush();\n-            out.close();\n-            return out.toByteArray();\n-        } catch (IOException e) {\n-            Log.w(TAG, \"Could not write bitmap\");\n-            return null;\n-        }\n-    }\n-\n-    /**\n-     * Try go guesstimate how much space the icon will take when serialized to avoid unnecessary\n-     * allocations/copies during the write (4 bytes per pixel).\n-     */\n-    static int getExpectedBitmapSize(Bitmap bitmap) {\n-        return bitmap.getWidth() * bitmap.getHeight() * 4;\n-    }\n-\n     public static int getArea(Region r) {\n         RegionIterator itr = new RegionIterator(r);\n         int area = 0;\n@@ -93,35 +58,4 @@ public class GraphicsUtils {\n     public static void noteNewBitmapCreated() {\n         sOnNewBitmapRunnable.run();\n     }\n-\n-\n-    /**\n-     * Returns the default path to be used by an icon\n-     */\n-    public static Path getShapePath(int size) {\n-        AdaptiveIconDrawable drawable = new AdaptiveIconDrawable(\n-                new ColorDrawable(Color.BLACK), new ColorDrawable(Color.BLACK));\n-        drawable.setBounds(0, 0, size, size);\n-        return new Path(drawable.getIconMask());\n-    }\n-\n-    /**\n-     * Returns the color associated with the attribute\n-     */\n-    public static int getAttrColor(Context context, int attr) {\n-        TypedArray ta = context.obtainStyledAttributes(new int[]{attr});\n-        int colorAccent = ta.getColor(0, 0);\n-        ta.recycle();\n-        return colorAccent;\n-    }\n-\n-    /**\n-     * Returns the alpha corresponding to the theme attribute {@param attr}\n-     */\n-    public static float getFloat(Context context, int attr, float defValue) {\n-        TypedArray ta = context.obtainStyledAttributes(new int[]{attr});\n-        float value = ta.getFloat(0, defValue);\n-        ta.recycle();\n-        return value;\n-    }\n }\n--- ShadowGenerator.java\n+++ ShadowGenerator.java\n@@ -35,14 +35,17 @@ public class ShadowGenerator {\n \n     public static final boolean ENABLE_SHADOWS = true;\n \n-    public static final float BLUR_FACTOR = 1.68f/48;\n+    //public static final float BLUR_FACTOR = 1.68f/48;\n+    public static final float BLUR_FACTOR = 0.5f/48;\n \n     // Percent of actual icon size\n     public static final float KEY_SHADOW_DISTANCE = 1f/48;\n-    private static final int KEY_SHADOW_ALPHA = 7;\n+    //private static final int KEY_SHADOW_ALPHA = 7;\n+    private static final int KEY_SHADOW_ALPHA = 61;\n     // Percent of actual icon size\n     private static final float HALF_DISTANCE = 0.5f;\n-    private static final int AMBIENT_SHADOW_ALPHA = 25;\n+    //private static final int AMBIENT_SHADOW_ALPHA = 25;\n+    private static final int AMBIENT_SHADOW_ALPHA = 30;\n \n     private final int mIconSize;\n \n"
  },
  {
    "path": "appiconloader-iconloaderlib/iconloaderlib-resources.patch",
    "content": "--- values/colors.xml\n+++ values/colors.xml\n@@ -18,7 +18,4 @@\n -->\n <resources>\n     <color name=\"legacy_icon_background\">#FFFFFF</color>\n-\n-    <!-- Yellow 600, used for highlighting \"important\" conversations in settings & notifications -->\n-    <color name=\"important_conversation\">#f9ab00</color>\n </resources>\n"
  },
  {
    "path": "appiconloader-iconloaderlib/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "appiconloader-iconloaderlib/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<manifest package=\"me.zhanghai.android.appiconloader.iconloaderlib\" />\n"
  },
  {
    "path": "build.gradle",
    "content": "buildscript {\n    repositories {\n        google()\n        mavenCentral()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:7.2.2'\n        classpath 'com.vanniktech:gradle-maven-publish-plugin:0.15.1'\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        mavenCentral()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "docs/contributing.md",
    "content": "# How to Contribute\n\nWe'd love to accept your patches and contributions to this project. There are\njust a few small guidelines you need to follow.\n\n## Contributor License Agreement\n\nContributions to this project must be accompanied by a Contributor License\nAgreement. You (or your employer) retain the copyright to your contribution;\nthis simply gives us permission to use and redistribute your contributions as\npart of the project. Head over to <https://cla.developers.google.com/> to see\nyour current agreements on file or to sign a new one.\n\nYou generally only need to submit a CLA once, so if you've already submitted one\n(even if it was for a different project), you probably don't need to do it\nagain.\n\n## Code reviews\n\nAll submissions, including submissions by project members, require review. We\nuse GitHub pull requests for this purpose. Consult\n[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more\ninformation on using pull requests.\n\n## Community Guidelines\n\nThis project follows [Google's Open Source Community\nGuidelines](https://opensource.google/conduct/).\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/1.txt",
    "content": "- Initial release.\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/2.txt",
    "content": "- Fixed crash when using shrinkNonAdaptiveIcons due to package name mismatch.\n- Added shrinkNonAdaptiveIcons as a parameter in APIs.\n- AppIconLoader.loadIcon() now returns the result Bitmap directly.\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/3.txt",
    "content": "- Enabled shape detection by default.\n- Moved the shrinkNonAdaptiveIcons parameter to AppIconLoader constructor.\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/4.txt",
    "content": "- Updated iconloaderlib to Android 11 source code.\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/5.txt",
    "content": "- Fixed MIUI \"optimization\" that draws an extra shadow.\n- Fixed the sample app to show all apps on Android 11.\n- Published library to Maven Central.\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/6.txt",
    "content": "- Synchronized iconloaderlib code from Android 12L.\n- Patched iconloaderlib to fix MIUI \"optimization\" reliably.\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/7.txt",
    "content": "- Migrated appiconloader-coil to Coil 2.\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/full_description.txt",
    "content": "https://github.com/zhanghai/AppIconLoader\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/short_description.txt",
    "content": "App icon loader from AOSP Launcher3\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/title.txt",
    "content": "AppIconLoader Sample\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Thu Sep 23 01:27:10 PDT 2021\ndistributionBase=GRADLE_USER_HOME\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-7.3.3-all.zip\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n\nandroid.enableJetifier=true\nandroid.useAndroidX=true\n\nGROUP=me.zhanghai.android.appiconloader\nVERSION_NAME=1.5.0\nVERSION_CODE=7\n\nPOM_DESCRIPTION=Android app icon loader from AOSP iconloaderlib\nPOM_INCEPTION_YEAR=2020\nPOM_LICENCE_NAME=The Apache Software License, Version 2.0\nPOM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt\nPOM_LICENCE_DIST=repo\nPOM_DEVELOPER_ID=zhanghai\nPOM_DEVELOPER_NAME=Hai Zhang\nPOM_DEVELOPER_URL=https://github.com/zhanghai\nPOM_SCM_CONNECTION=scm:git@github.com:zhanghai/AppIconLoader.git\nPOM_SCM_DEV_CONNECTION=scm:git@github.com:zhanghai/AppIconLoader.git\nPOM_SCM_URL=https://github.com/zhanghai/AppIconLoader\nPOM_URL=https://github.com/zhanghai/AppIconLoader\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "sample/.gitignore",
    "content": "/.externalNativeBuild/\n/build/\n/out/\n"
  },
  {
    "path": "sample/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 33\n    buildToolsVersion '33.0.0'\n    defaultConfig {\n        applicationId 'me.zhanghai.android.appiconloader.sample'\n        minSdkVersion 21\n        targetSdkVersion 33\n        versionCode Integer.parseInt(VERSION_CODE)\n        versionName VERSION_NAME\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    viewBinding {\n        enabled = true\n    }\n    signingConfigs {\n        release {\n            storeFile file(System.getenv('SAMPLE_STORE_FILE') ?: '/dev/null')\n            storePassword System.getenv('SAMPLE_STORE_PASSWORD')\n            keyAlias System.getenv('SAMPLE_KEY_ALIAS')\n            keyPassword System.getenv('SAMPLE_KEY_PASSWORD')\n        }\n    }\n    buildTypes {\n        release {\n            minifyEnabled true\n            shrinkResources true\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n            signingConfig signingConfigs.release\n        }\n    }\n}\n\ndependencies {\n    implementation 'androidx.appcompat:appcompat:1.5.0'\n    def androidx_lifecycle_version = '2.5.1'\n    implementation \"androidx.lifecycle:lifecycle-viewmodel:$androidx_lifecycle_version\"\n    implementation \"androidx.lifecycle:lifecycle-livedata:$androidx_lifecycle_version\"\n    implementation \"androidx.lifecycle:lifecycle-common-java8:$androidx_lifecycle_version\"\n    implementation 'androidx.recyclerview:recyclerview:1.2.1'\n    implementation 'com.google.android.material:material:1.6.1'\n    def glide_version = '4.13.2'\n    implementation \"com.github.bumptech.glide:glide:$glide_version\"\n    annotationProcessor \"com.github.bumptech.glide:compiler:$glide_version\"\n    implementation 'io.coil-kt:coil:2.2.0'\n    implementation 'me.zhanghai.android.fastscroll:library:1.1.8'\n    implementation project(':appiconloader')\n    implementation project(':appiconloader-coil')\n    implementation project(':appiconloader-glide')\n}\n"
  },
  {
    "path": "sample/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n\n# Glide\n-keep public class * implements com.bumptech.glide.module.GlideModule\n-keep public class * extends com.bumptech.glide.module.AppGlideModule\n-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {\n  **[] $VALUES;\n  public *;\n}\n"
  },
  {
    "path": "sample/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<manifest\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"me.zhanghai.android.appiconloader.sample\">\n\n    <uses-permission\n        android:name=\"android.permission.QUERY_ALL_PACKAGES\"\n        tools:ignore=\"QueryAllPackagesPermission\" />\n\n    <application\n        android:allowBackup=\"true\"\n        android:fullBackupContent=\"true\"\n        android:icon=\"@mipmap/launcher_icon\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/launcher_icon\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/Theme.Sample\">\n\n        <activity\n            android:name=\".MainActivity\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n</manifest>\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/AppGlideModule.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.graphics.Bitmap;\n\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.Registry;\nimport com.bumptech.glide.annotation.GlideModule;\n\nimport androidx.annotation.NonNull;\nimport me.zhanghai.android.appiconloader.glide.AppIconModelLoader;\n\n@GlideModule\npublic class AppGlideModule extends com.bumptech.glide.module.AppGlideModule {\n    @Override\n    public boolean isManifestParsingEnabled() {\n        return false;\n    }\n\n    @Override\n    public void registerComponents(@NonNull Context context, @NonNull Glide glide,\n                                   @NonNull Registry registry) {\n        int iconSize = context.getResources().getDimensionPixelSize(R.dimen.app_icon_size);\n        registry.prepend(PackageInfo.class, Bitmap.class, new AppIconModelLoader.Factory(iconSize,\n                false, context));\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/AppListAdapter.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.content.pm.PackageInfo;\nimport android.view.LayoutInflater;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.content.pm.PackageInfoCompat;\nimport androidx.core.util.Pair;\nimport androidx.recyclerview.widget.RecyclerView;\nimport me.zhanghai.android.appiconloader.sample.databinding.AppItemBinding;\nimport me.zhanghai.android.fastscroll.PopupTextProvider;\n\npublic class AppListAdapter extends RecyclerView.Adapter<AppListAdapter.ViewHolder>\n        implements PopupTextProvider {\n    @NonNull\n    private final IconLoader mIconLoader;\n\n    @NonNull\n    private final List<Pair<PackageInfo, String>> mApps = new ArrayList<>();\n\n    public AppListAdapter(@NonNull IconLoader iconLoader) {\n        mIconLoader = iconLoader;\n\n        setHasStableIds(true);\n    }\n\n    public void replace(@NonNull List<Pair<PackageInfo, String>> apps) {\n        mApps.clear();\n        mApps.addAll(apps);\n        notifyDataSetChanged();\n    }\n\n    @Override\n    public int getItemCount() {\n        return mApps.size();\n    }\n\n    @NonNull\n    private Pair<PackageInfo, String> getItem(int position) {\n        return mApps.get(position);\n    }\n\n    @Override\n    public long getItemId(int position) {\n        PackageInfo packageInfo = getItem(position).first;\n        return Objects.hash(packageInfo.packageName, PackageInfoCompat.getLongVersionCode(\n                packageInfo), packageInfo.applicationInfo.uid);\n    }\n\n    @NonNull\n    @Override\n    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        return new ViewHolder(AppItemBinding.inflate(LayoutInflater.from(parent.getContext()),\n                parent, false));\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n        Pair<PackageInfo, String> app = getItem(position);\n        PackageInfo packageInfo = app.first;\n        String label = app.second;\n        mIconLoader.loadIcon(holder.binding.iconImage, packageInfo);\n        holder.binding.labelText.setText(label);\n        holder.binding.descriptionText.setText(\n                holder.binding.descriptionText.getContext().getString(\n                        R.string.app_description_format, packageInfo.packageName,\n                        packageInfo.applicationInfo.uid));\n        holder.binding.getRoot().setOnClickListener(view -> AppListLoader.startAppDetailsActivity(\n                packageInfo, view.getContext()));\n    }\n\n    @NonNull\n    @Override\n    public String getPopupText(int position) {\n        String label = getItem(position).second;\n        return label.substring(0, label.offsetByCodePoints(0, 1)).toUpperCase(Locale.getDefault());\n    }\n\n    public interface IconLoader {\n        void loadIcon(@NonNull ImageView imageView, @NonNull PackageInfo packageInfo);\n    }\n\n    static class ViewHolder extends RecyclerView.ViewHolder {\n        public final AppItemBinding binding;\n\n        public ViewHolder(@NonNull AppItemBinding binding) {\n            super(binding.getRoot());\n\n            this.binding = binding;\n        }\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/AppListFragment.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport me.zhanghai.android.appiconloader.sample.databinding.AppListFragmentBinding;\nimport me.zhanghai.android.fastscroll.FastScrollerBuilder;\n\npublic abstract class AppListFragment extends Fragment {\n    private AppListFragmentBinding mBinding;\n\n    private AppListAdapter mAdapter;\n\n    private AppListViewModel mViewModel;\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,\n                             @Nullable Bundle savedInstanceState) {\n        mBinding = AppListFragmentBinding.inflate(inflater, container, false);\n        return mBinding.getRoot();\n    }\n\n    @Override\n    public void onActivityCreated(@Nullable Bundle savedInstanceState) {\n        super.onActivityCreated(savedInstanceState);\n\n        Activity activity = requireActivity();\n        mBinding.recycler.setLayoutManager(new LinearLayoutManager(activity));\n        mAdapter = new AppListAdapter(onCreateIconLoader());\n        mBinding.recycler.setAdapter(mAdapter);\n        new FastScrollerBuilder(mBinding.recycler).useMd2Style().build();\n\n        mViewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(\n                activity.getApplication())).get(AppListViewModel.class);\n        mViewModel.getAppListLiveData().observe(getViewLifecycleOwner(), apps -> {\n            mBinding.progress.setVisibility(View.GONE);\n            mAdapter.replace(apps);\n        });\n    }\n\n    @NonNull\n    protected abstract AppListAdapter.IconLoader onCreateIconLoader();\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/AppListLiveData.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.os.AsyncTask;\n\nimport java.util.List;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.util.Pair;\nimport androidx.lifecycle.LiveData;\n\npublic class AppListLiveData extends LiveData<List<Pair<PackageInfo, String>>> {\n    private final Context mContext;\n\n    public AppListLiveData(@NonNull Context context) {\n        mContext = context.getApplicationContext();\n\n        loadValue();\n    }\n\n    private void loadValue() {\n        AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {\n            List<Pair<PackageInfo, String>> value = AppListLoader.loadAppList(mContext);\n            postValue(value);\n        });\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/AppListLoader.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.LauncherActivityInfo;\nimport android.content.pm.LauncherApps;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Process;\nimport android.os.UserHandle;\nimport android.util.ArrayMap;\n\nimport java.text.Collator;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.content.ContextCompat;\nimport androidx.core.util.Pair;\n\npublic class AppListLoader {\n    private AppListLoader() {}\n\n    @NonNull\n    public static List<Pair<PackageInfo, String>> loadAppList(@NonNull Context context) {\n        PackageManager packageManager = context.getPackageManager();\n        List<PackageInfo> packageInfos = packageManager.getInstalledPackages(0);\n        Iterator<PackageInfo> iterator = packageInfos.iterator();\n        while (iterator.hasNext()) {\n            PackageInfo packageInfo = iterator.next();\n            if (packageInfo.applicationInfo == null) {\n                iterator.remove();\n            }\n        }\n\n        LauncherApps launcherApps = ContextCompat.getSystemService(context, LauncherApps.class);\n        List<UserHandle> profiles = LauncherAppsCompat.getProfiles(launcherApps, context);\n        profiles.remove(Process.myUserHandle());\n        if (!profiles.isEmpty()) {\n            ArrayMap<String, PackageInfo> packageInfoMap = new ArrayMap<>();\n            for (PackageInfo packageInfo : packageInfos) {\n                packageInfoMap.put(packageInfo.packageName, packageInfo);\n            }\n            for (UserHandle profile : profiles) {\n                List<LauncherActivityInfo> activityList = launcherApps.getActivityList(null,\n                        profile);\n                ArrayMap<String, ApplicationInfo> applicationInfoMap = new ArrayMap<>();\n                for (LauncherActivityInfo launcherActivityInfo : activityList) {\n                    ApplicationInfo applicationInfo = launcherActivityInfo.getApplicationInfo();\n                    if (!applicationInfoMap.containsKey(applicationInfo.packageName)) {\n                        applicationInfoMap.put(applicationInfo.packageName, applicationInfo);\n                    }\n                }\n                for (ApplicationInfo applicationInfo : applicationInfoMap.values()) {\n                    PackageInfo packageInfo;\n                    String packageName = applicationInfo.packageName;\n                    if (packageInfoMap.containsKey(packageName)) {\n                        packageInfo = ParcelableCloner.cloneParcelable(packageInfoMap.get(\n                                packageName), PackageInfo.class.getClassLoader());\n                    } else {\n                        try {\n                            packageInfo = packageManager.getPackageInfo(packageName,\n                                    PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES);\n                        } catch (PackageManager.NameNotFoundException e) {\n                            continue;\n                        }\n                    }\n                    packageInfo.applicationInfo = applicationInfo;\n                    packageInfos.add(packageInfo);\n                }\n            }\n        }\n\n        List<Pair<PackageInfo, String>> apps = new ArrayList<>();\n        for (PackageInfo packageInfo : packageInfos) {\n            String label = packageInfo.applicationInfo.loadLabel(packageManager).toString();\n            apps.add(new Pair<>(packageInfo, label));\n        }\n        Collator collator = Collator.getInstance();\n        Collections.sort(apps, (first, second) -> {\n            int result = collator.compare(first.second, second.second);\n            if (result == 0) {\n                result = first.first.packageName.compareTo(second.first.packageName);\n            }\n            if (result == 0) {\n                result = Integer.compare(first.first.applicationInfo.uid,\n                        second.first.applicationInfo.uid);\n            }\n            return result;\n        });\n        return apps;\n    }\n\n    public static void startAppDetailsActivity(@NonNull PackageInfo packageInfo,\n                                               @NonNull Context context) {\n        LauncherApps launcherApps = ContextCompat.getSystemService(context, LauncherApps.class);\n        ComponentName componentName = new ComponentName(packageInfo.packageName, \"\");\n        UserHandle user = UserHandleCompat.getUserHandleForUid(packageInfo.applicationInfo.uid);\n        launcherApps.startAppDetailsActivity(componentName, user, null, null);\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/AppListViewModel.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.app.Application;\nimport android.content.pm.PackageInfo;\n\nimport java.util.List;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.util.Pair;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\n\npublic class AppListViewModel extends AndroidViewModel {\n    @NonNull\n    private final AppListLiveData mAppListLiveData;\n\n    public AppListViewModel(@NonNull Application application) {\n        super(application);\n\n        mAppListLiveData = new AppListLiveData(application);\n    }\n\n    @NonNull\n    public LiveData<List<Pair<PackageInfo, String>>> getAppListLiveData() {\n        return mAppListLiveData;\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/CoilAppListFragment.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.content.Context;\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport coil.Coil;\nimport coil.ImageLoader;\nimport coil.request.ImageRequest;\n\npublic class CoilAppListFragment extends AppListFragment {\n    @NonNull\n    public static CoilAppListFragment newInstance() {\n        return new CoilAppListFragment();\n    }\n\n    @Override\n    public void onActivityCreated(@Nullable Bundle savedInstanceState) {\n        super.onActivityCreated(savedInstanceState);\n\n        CoilInitializer.initializeCoil(requireContext().getApplicationContext());\n    }\n\n    @NonNull\n    @Override\n    protected AppListAdapter.IconLoader onCreateIconLoader() {\n        return (imageView, packageInfo) -> {\n            Context context = imageView.getContext();\n            ImageLoader loader = Coil.imageLoader(context);\n            loader.enqueue(new ImageRequest.Builder(context)\n                    .data(packageInfo)\n                    .target(imageView)\n                    .build());\n        };\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/CoilInitializer.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\n\nimport androidx.annotation.NonNull;\nimport coil.Coil;\nimport coil.ComponentRegistry;\nimport coil.ImageLoader;\nimport me.zhanghai.android.appiconloader.coil.AppIconFetcher;\nimport me.zhanghai.android.appiconloader.coil.AppIconKeyer;\n\npublic class CoilInitializer {\n    private static boolean sInitialized = false;\n    @NonNull\n    private static final Object sInitializedLock = new Object();\n\n    private CoilInitializer() {}\n\n    public static void initializeCoil(@NonNull Context context) {\n        synchronized (sInitializedLock) {\n            if (sInitialized) {\n                return;\n            }\n            context = context.getApplicationContext();\n            int iconSize = context.getResources().getDimensionPixelSize(R.dimen.app_icon_size);\n            Coil.setImageLoader(new ImageLoader.Builder(context)\n                    .components(new ComponentRegistry.Builder()\n                            .add(new AppIconKeyer(), PackageInfo.class)\n                            .add(new AppIconFetcher.Factory(iconSize, false, context),\n                                    PackageInfo.class)\n                            .build())\n                    .build());\n            sInitialized = true;\n        }\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/CoordinatorScrollingFrameLayout.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.WindowInsets;\nimport android.widget.FrameLayout;\n\nimport com.google.android.material.appbar.AppBarLayout;\n\nimport androidx.annotation.AttrRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StyleRes;\nimport androidx.coordinatorlayout.widget.CoordinatorLayout;\nimport androidx.core.graphics.Insets;\nimport androidx.core.view.WindowInsetsCompat;\n\npublic class CoordinatorScrollingFrameLayout extends FrameLayout\n        implements CoordinatorLayout.AttachedBehavior {\n    public CoordinatorScrollingFrameLayout(@NonNull Context context) {\n        super(context);\n    }\n\n    public CoordinatorScrollingFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public CoordinatorScrollingFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs,\n                                           @AttrRes int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    public CoordinatorScrollingFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs,\n                                           @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    @NonNull\n    @Override\n    public WindowInsets dispatchApplyWindowInsets(@NonNull WindowInsets insets) {\n        insets = new WindowInsetsCompat.Builder(WindowInsetsCompat.toWindowInsetsCompat(insets))\n                .setSystemWindowInsets(Insets.of(insets.getSystemWindowInsetLeft(), 0,\n                        insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()))\n                .build()\n                .toWindowInsets();\n        super.dispatchApplyWindowInsets(insets);\n        return insets;\n    }\n\n    @NonNull\n    @Override\n    public WindowInsets onApplyWindowInsets(@NonNull WindowInsets insets) {\n        return insets;\n    }\n\n    @NonNull\n    @Override\n    public CoordinatorLayout.Behavior getBehavior() {\n        return new Behavior();\n    }\n\n    private static class Behavior extends AppBarLayout.ScrollingViewBehavior {\n        @Override\n        public boolean onMeasureChild(@NonNull CoordinatorLayout parent, @NonNull View child,\n                                      int parentWidthMeasureSpec, int widthUsed,\n                                      int parentHeightMeasureSpec, int heightUsed) {\n            @SuppressLint(\"RestrictedApi\")\n            WindowInsetsCompat parentInsets = parent.getLastWindowInsets();\n            if (parentInsets != null) {\n                int parentHeightSize = View.MeasureSpec.getSize(parentHeightMeasureSpec);\n                parentHeightSize -= parentInsets.getSystemWindowInsetTop()\n                        + parentInsets.getSystemWindowInsetBottom();\n                int parentHeightMode = View.MeasureSpec.getMode(parentHeightMeasureSpec);\n                parentHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(parentHeightSize,\n                        parentHeightMode);\n            }\n            return super.onMeasureChild(parent, child, parentWidthMeasureSpec, widthUsed,\n                    parentHeightMeasureSpec, heightUsed);\n        }\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/FastScrollerLiftOnScrollHack.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport com.google.android.material.appbar.AppBarLayout;\n\nimport androidx.annotation.NonNull;\nimport androidx.coordinatorlayout.widget.CoordinatorLayout;\n\npublic class FastScrollerLiftOnScrollHack {\n    private FastScrollerLiftOnScrollHack() {}\n\n    public static void hack(@NonNull AppBarLayout appBarLayout, int liftOnScrollTargetViewId) {\n        appBarLayout.getViewTreeObserver().addOnPreDrawListener(() -> {\n            // Invalidate the cached view reference so that this works after replacing fragment.\n            appBarLayout.setLiftOnScrollTargetViewId(liftOnScrollTargetViewId);\n            // Call AppBarLayout.Behavior.onNestedPreScroll() with dy == 0 to update lifted state.\n            CoordinatorLayout.Behavior behavior =\n                    ((CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams()).getBehavior();\n            CoordinatorLayout coordinatorLayout = (CoordinatorLayout) appBarLayout.getParent();\n            behavior.onNestedPreScroll(coordinatorLayout, appBarLayout, coordinatorLayout, 0, 0,\n                    null, 0);\n            return true;\n        });\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/GlideAppListFragment.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport androidx.annotation.NonNull;\n\npublic class GlideAppListFragment extends AppListFragment {\n    @NonNull\n    public static GlideAppListFragment newInstance() {\n        return new GlideAppListFragment();\n    }\n\n    @NonNull\n    @Override\n    protected AppListAdapter.IconLoader onCreateIconLoader() {\n        return (imageView, packageInfo) -> GlideApp.with(imageView)\n                .load(packageInfo)\n                .into(imageView);\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/LauncherAppsCompat.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.content.Context;\nimport android.content.pm.LauncherApps;\nimport android.os.Build;\nimport android.os.UserHandle;\nimport android.os.UserManager;\n\nimport java.util.List;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.content.ContextCompat;\n\npublic class LauncherAppsCompat {\n    private LauncherAppsCompat() {}\n\n    @NonNull\n    public static List<UserHandle> getProfiles(@NonNull LauncherApps launcherApps,\n                                               @NonNull Context context) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            return launcherApps.getProfiles();\n        } else {\n            UserManager userManager = ContextCompat.getSystemService(context, UserManager.class);\n            return userManager.getUserProfiles();\n        }\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/MainActivity.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.AppCompatActivity;\n\npublic class MainActivity extends AppCompatActivity {\n    @NonNull\n    private MainFragment mMainFragment;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Calls ensureSubDecor().\n        findViewById(android.R.id.content);\n\n        if (savedInstanceState == null) {\n            mMainFragment = MainFragment.newInstance();\n            getSupportFragmentManager().beginTransaction()\n                    .add(android.R.id.content, mMainFragment)\n                    .commit();\n        } else {\n            mMainFragment = (MainFragment) getSupportFragmentManager().findFragmentById(\n                    android.R.id.content);\n        }\n    }\n\n    @Override\n    public void onBackPressed() {\n        if (mMainFragment.onBackPressed()) {\n            return;\n        }\n        super.onBackPressed();\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/MainFragment.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.content.ActivityNotFoundException;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Toast;\n\nimport androidx.annotation.IdRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.core.view.GravityCompat;\nimport androidx.fragment.app.Fragment;\nimport me.zhanghai.android.appiconloader.sample.databinding.MainFragmentBinding;\n\npublic class MainFragment extends Fragment {\n    private static final Uri GITHUB_URI = Uri.parse(\"https://github.com/zhanghai/AppIconLoader\");\n\n    private MainFragmentBinding mBinding;\n\n    @NonNull\n    public static MainFragment newInstance() {\n        return new MainFragment();\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setHasOptionsMenu(true);\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,\n                             @Nullable Bundle savedInstanceState) {\n        mBinding = MainFragmentBinding.inflate(inflater, container, false);\n        return mBinding.getRoot();\n    }\n\n    @Override\n    public void onActivityCreated(@Nullable Bundle savedInstanceState) {\n        super.onActivityCreated(savedInstanceState);\n\n        AppCompatActivity activity = (AppCompatActivity) requireActivity();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            View decorView = activity.getWindow().getDecorView();\n            decorView.setSystemUiVisibility(decorView.getSystemUiVisibility()\n                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION\n                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);\n        }\n\n        activity.setSupportActionBar(mBinding.toolbar);\n\n        if (savedInstanceState == null) {\n            setNavigationCheckedItem(R.id.glide);\n        }\n        mBinding.navigationView.setNavigationItemSelectedListener(this::onNavigationItemSelected);\n\n        FastScrollerLiftOnScrollHack.hack(mBinding.appBarLayout, R.id.recycler);\n    }\n\n    @Override\n    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {\n        inflater.inflate(R.menu.main, menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        switch (item.getItemId()) {\n            case android.R.id.home:\n                mBinding.drawerLayout.openDrawer(GravityCompat.START);\n                return true;\n            case R.id.action_view_on_github:\n                viewOnGitHub();\n                return true;\n            default:\n                return super.onOptionsItemSelected(item);\n        }\n    }\n\n    private void viewOnGitHub() {\n        try {\n            startActivity(new Intent(Intent.ACTION_VIEW, GITHUB_URI));\n        } catch (ActivityNotFoundException e) {\n            e.printStackTrace();\n            Toast.makeText(requireContext(), e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();\n        }\n    }\n\n    private boolean onNavigationItemSelected(@NonNull MenuItem item) {\n        int itemId = item.getItemId();\n        switch (item.getItemId()) {\n            case R.id.glide:\n            case R.id.coil:\n            case R.id.synchronous:\n                setNavigationCheckedItem(itemId);\n                mBinding.drawerLayout.closeDrawer(GravityCompat.START);\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    private void setNavigationCheckedItem(@IdRes int itemId) {\n        MenuItem item = mBinding.navigationView.getCheckedItem();\n        if (item != null && item.getItemId() == itemId) {\n            return;\n        }\n        Fragment fragment;\n        switch (itemId) {\n            case R.id.glide:\n                fragment = GlideAppListFragment.newInstance();\n                break;\n            case R.id.coil:\n                fragment = CoilAppListFragment.newInstance();\n                break;\n            case R.id.synchronous:\n                fragment = SynchronousAppListFragment.newInstance();\n                break;\n            default:\n                throw new AssertionError(itemId);\n        }\n        getChildFragmentManager().beginTransaction()\n                .replace(R.id.containerLayout, fragment)\n                .commit();\n        mBinding.navigationView.setCheckedItem(itemId);\n    }\n\n    public boolean onBackPressed() {\n        if (mBinding.drawerLayout.isDrawerOpen(GravityCompat.START)) {\n            mBinding.drawerLayout.closeDrawer(GravityCompat.START);\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/NewDispatchApplyWindowInsetsFrameLayout.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.WindowInsets;\nimport android.widget.FrameLayout;\n\nimport androidx.annotation.AttrRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StyleRes;\n\npublic class NewDispatchApplyWindowInsetsFrameLayout extends FrameLayout {\n    public NewDispatchApplyWindowInsetsFrameLayout(@NonNull Context context) {\n        super(context);\n    }\n\n    public NewDispatchApplyWindowInsetsFrameLayout(@NonNull Context context,\n                                                   @Nullable AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public NewDispatchApplyWindowInsetsFrameLayout(@NonNull Context context,\n                                                   @Nullable AttributeSet attrs,\n                                                   @AttrRes int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    public NewDispatchApplyWindowInsetsFrameLayout(@NonNull Context context,\n                                                   @Nullable AttributeSet attrs,\n                                                   @AttrRes int defStyleAttr,\n                                                   @StyleRes int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    @NonNull\n    @Override\n    public WindowInsets dispatchApplyWindowInsets(@NonNull WindowInsets insets) {\n        for (int i = 0, count = getChildCount(); i < count; ++i) {\n            getChildAt(i).dispatchApplyWindowInsets(insets);\n        }\n        return insets;\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/PackageManagerCompat.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.content.pm.PackageManager;\nimport android.os.Build;\n\npublic class PackageManagerCompat {\n    private PackageManagerCompat() {}\n\n    public static final int MATCH_UNINSTALLED_PACKAGES =\n            Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ?\n                    PackageManager.MATCH_UNINSTALLED_PACKAGES\n                    : PackageManager.GET_UNINSTALLED_PACKAGES;\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/ParcelableCloner.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.Nullable;\n\npublic class ParcelableCloner {\n    private ParcelableCloner() {}\n\n    public static <T extends Parcelable> T cloneParcelable(T parcelable,\n                                                           @Nullable ClassLoader classLoader) {\n        Parcel parcel = Parcel.obtain();\n        try {\n            parcel.writeParcelable(parcelable, 0);\n            parcel.setDataPosition(0);\n            return parcel.readParcelable(classLoader);\n        } finally {\n            parcel.recycle();\n        }\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/SynchronousAppListFragment.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.content.Context;\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport me.zhanghai.android.appiconloader.AppIconLoader;\n\npublic class SynchronousAppListFragment extends AppListFragment {\n    private AppIconLoader mAppIconLoader;\n\n    @NonNull\n    public static SynchronousAppListFragment newInstance() {\n        return new SynchronousAppListFragment();\n    }\n\n    @Override\n    public void onActivityCreated(@Nullable Bundle savedInstanceState) {\n        super.onActivityCreated(savedInstanceState);\n\n        Context context = requireContext();\n        mAppIconLoader = new AppIconLoader(context.getResources().getDimensionPixelSize(\n                R.dimen.app_icon_size), false, context.getApplicationContext());\n    }\n\n    @NonNull\n    @Override\n    protected AppListAdapter.IconLoader onCreateIconLoader() {\n        return (imageView, packageInfo) -> imageView.setImageBitmap(mAppIconLoader.loadIcon(\n                packageInfo.applicationInfo));\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/zhanghai/android/appiconloader/sample/UserHandleCompat.java",
    "content": "/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.zhanghai.android.appiconloader.sample;\n\nimport android.os.Build;\nimport android.os.UserHandle;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.InvocationTargetException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\npublic class UserHandleCompat {\n    private static final int PER_USER_RANGE = 100000;\n    private static final int USER_SYSTEM = 0;\n    private static final boolean MU_ENABLED = true;\n\n    @Nullable\n    private static Constructor<UserHandle> sConstructor;\n    @NonNull\n    private static final Object sConstructorLock = new Object();\n\n    private UserHandleCompat() {}\n\n    @NonNull\n    public static UserHandle getUserHandleForUid(int uid) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            return UserHandle.getUserHandleForUid(uid);\n        } else {\n            int userId = getUserId(uid);\n            Constructor<UserHandle> constructor = getConstructor();\n            try {\n                return constructor.newInstance(userId);\n            } catch (IllegalAccessException | InstantiationException\n                    | InvocationTargetException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    private static int getUserId(int uid) {\n        if (MU_ENABLED) {\n            return uid / PER_USER_RANGE;\n        } else {\n            return USER_SYSTEM;\n        }\n    }\n\n    @NonNull\n    private static Constructor<UserHandle> getConstructor() {\n        synchronized (sConstructorLock) {\n            if (sConstructor == null) {\n                try {\n                    sConstructor = UserHandle.class.getDeclaredConstructor(int.class);\n                } catch (NoSuchMethodException e) {\n                    throw new RuntimeException(e);\n                }\n            }\n            return sConstructor;\n        }\n    }\n}\n"
  },
  {
    "path": "sample/src/main/res/drawable/info_icon_control_normal_24dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?colorControlNormal\">\n\n    <path\n        android:fillColor=\"#FF000000\"\n        android:pathData=\"M11 7h2v2h-2zm0 4h2v6h-2zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z\" />\n</vector>\n"
  },
  {
    "path": "sample/src/main/res/drawable/menu_icon_control_normal_24dp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?colorControlNormal\">\n\n    <path\n        android:fillColor=\"#FF000000\"\n        android:pathData=\"M3,18h18v-2H3v2zm0,-5h18v-2H3v2zm0,-7v2h18V6H3z\" />\n</vector>\n"
  },
  {
    "path": "sample/src/main/res/layout/app_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?listPreferredItemHeight\"\n    android:paddingStart=\"?listPreferredItemPaddingStart\"\n    android:paddingEnd=\"?listPreferredItemPaddingEnd\"\n    android:background=\"?selectableItemBackground\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"horizontal\">\n\n    <ImageView\n        android:id=\"@+id/iconImage\"\n        android:layout_width=\"@dimen/app_icon_size\"\n        android:layout_height=\"@dimen/app_icon_size\" />\n\n    <LinearLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:layout_marginStart=\"?listPreferredItemPaddingStart\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/labelText\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:ellipsize=\"end\"\n            android:maxLines=\"1\"\n            android:textAppearance=\"@style/TextAppearance.MaterialComponents.Body1\" />\n\n        <TextView\n            android:id=\"@+id/descriptionText\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:ellipsize=\"end\"\n            android:maxLines=\"1\"\n            android:textAppearance=\"@style/TextAppearance.MaterialComponents.Body2\"\n            android:textColor=\"?android:textColorSecondary\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "sample/src/main/res/layout/app_list_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<me.zhanghai.android.appiconloader.sample.NewDispatchApplyWindowInsetsFrameLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:fitsSystemWindows=\"true\">\n\n        <ProgressBar\n            android:id=\"@+id/progress\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\" />\n    </FrameLayout>\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/recycler\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:clipToPadding=\"false\"\n        android:fitsSystemWindows=\"true\" />\n</me.zhanghai.android.appiconloader.sample.NewDispatchApplyWindowInsetsFrameLayout>\n"
  },
  {
    "path": "sample/src/main/res/layout/main_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<androidx.drawerlayout.widget.DrawerLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/drawerLayout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\">\n\n    <androidx.coordinatorlayout.widget.CoordinatorLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:fitsSystemWindows=\"true\">\n\n        <com.google.android.material.appbar.AppBarLayout\n            android:id=\"@+id/appBarLayout\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"?colorSurface\"\n            android:fitsSystemWindows=\"true\"\n            android:theme=\"?actionBarTheme\"\n            app:liftOnScroll=\"true\"\n            app:liftOnScrollTargetViewId=\"@id/recycler\">\n\n            <androidx.appcompat.widget.Toolbar\n                android:id=\"@+id/toolbar\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"?actionBarSize\"\n                app:navigationIcon=\"@drawable/menu_icon_control_normal_24dp\"\n                app:popupTheme=\"?actionBarPopupTheme\" />\n        </com.google.android.material.appbar.AppBarLayout>\n\n        <me.zhanghai.android.appiconloader.sample.CoordinatorScrollingFrameLayout\n            android:id=\"@+id/containerLayout\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:fitsSystemWindows=\"true\" />\n    </androidx.coordinatorlayout.widget.CoordinatorLayout>\n\n    <com.google.android.material.navigation.NavigationView\n        android:id=\"@+id/navigationView\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        app:insetForeground=\"@null\"\n        app:menu=\"@menu/navigation\" />\n</androidx.drawerlayout.widget.DrawerLayout>\n"
  },
  {
    "path": "sample/src/main/res/menu/main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<menu\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/action_view_on_github\"\n        android:icon=\"@drawable/info_icon_control_normal_24dp\"\n        android:orderInCategory=\"100\"\n        android:title=\"@string/view_on_github\"\n        app:showAsAction=\"always\" />\n</menu>\n"
  },
  {
    "path": "sample/src/main/res/menu/navigation.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <group android:checkableBehavior=\"single\">\n\n        <item\n            android:id=\"@+id/glide\"\n            android:title=\"@string/glide\" />\n\n        <item\n            android:id=\"@+id/coil\"\n            android:title=\"@string/coil\" />\n\n        <item\n            android:id=\"@+id/synchronous\"\n            android:title=\"@string/synchronous\" />\n    </group>\n</menu>\n"
  },
  {
    "path": "sample/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<resources>\n\n    <color name=\"color_secondary_light\">#009688</color>\n    <color name=\"color_secondary_dark\">#80cbc4</color>\n    <color name=\"color_secondary\">@color/color_secondary_light</color>\n\n    <color name=\"system_window_scrim_light\">#99FFFFFF</color>\n    <color name=\"system_window_scrim_dark\">#52000000</color>\n    <color name=\"system_window_scrim\">@color/system_window_scrim_light</color>\n\n    <color name=\"system_window_scrim_compat_light\">#BBBBBB</color>\n    <color name=\"system_window_scrim_compat\">@color/system_window_scrim_compat_light</color>\n</resources>\n"
  },
  {
    "path": "sample/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<resources>\n    <dimen name=\"app_icon_size\">40dp</dimen>\n</resources>\n"
  },
  {
    "path": "sample/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<resources>\n    <string name=\"app_name\">AppIconLoader Sample</string>\n\n    <string name=\"glide\">Glide</string>\n    <string name=\"coil\">Coil</string>\n    <string name=\"synchronous\">Synchronous (laggy)</string>\n    <string name=\"view_on_github\">View on GitHub</string>\n    <string name=\"app_description_format\">%1$s (%2$d)</string>\n</resources>\n"
  },
  {
    "path": "sample/src/main/res/values/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<resources>\n    <style name=\"Platform.V21.Theme.Sample\" parent=\"Theme.MaterialComponents.DayNight\">\n        <item name=\"colorPrimaryDark\">@color/system_window_scrim_compat</item>\n    </style>\n    <style name=\"Platform.Theme.Sample\" parent=\"Platform.V21.Theme.Sample\" />\n    <style name=\"Base.Theme.Sample\" parent=\"Platform.Theme.Sample\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n        <item name=\"colorPrimary\">?colorSecondary</item>\n        <item name=\"colorOnPrimary\">?colorOnSecondary</item>\n        <item name=\"colorSecondary\">@color/color_secondary</item>\n    </style>\n    <style name=\"Theme.Sample\" parent=\"Base.Theme.Sample\" />\n</resources>\n"
  },
  {
    "path": "sample/src/main/res/values-night/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<resources>\n\n    <color name=\"color_secondary\">@color/color_secondary_dark</color>\n\n    <color name=\"system_window_scrim\">@color/system_window_scrim_dark</color>\n\n    <color name=\"system_window_scrim_compat\">@color/system_window_scrim_dark</color>\n</resources>\n"
  },
  {
    "path": "sample/src/main/res/values-v23/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<resources>\n    <style name=\"Platform.V23.Theme.Sample\" parent=\"Platform.V21.Theme.Sample\">\n        <item name=\"colorPrimaryDark\">@color/system_window_scrim</item>\n        <item name=\"android:windowLightStatusBar\">?isLightTheme</item>\n    </style>\n    <style name=\"Platform.Theme.Sample\" parent=\"Platform.V23.Theme.Sample\" />\n</resources>\n"
  },
  {
    "path": "sample/src/main/res/values-v27/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<resources>\n    <style name=\"Platform.V27.Theme.Sample\" parent=\"Platform.V23.Theme.Sample\">\n        <item name=\"android:navigationBarColor\">?colorPrimaryDark</item>\n        <item name=\"android:windowLightNavigationBar\">?isLightTheme</item>\n    </style>\n    <style name=\"Platform.Theme.Sample\" parent=\"Platform.V27.Theme.Sample\" />\n</resources>\n"
  },
  {
    "path": "sample/src/main/res/values-v29/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ Copyright 2020 Google LLC\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     https://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<resources>\n    <style name=\"Platform.V29.Theme.Sample\" parent=\"Platform.V27.Theme.Sample\">\n        <item name=\"colorPrimaryDark\">@android:color/transparent</item>\n    </style>\n    <style name=\"Platform.Theme.Sample\" parent=\"Platform.V29.Theme.Sample\" />\n</resources>\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':appiconloader', ':appiconloader-coil', ':appiconloader-glide', ':appiconloader-iconloaderlib', ':sample'\n"
  }
]