├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── ooo │ │ └── oxo │ │ └── apps │ │ └── materialize │ │ ├── AboutActivity.java │ │ ├── AdjustActivity.java │ │ ├── AdjustViewModel.java │ │ ├── AppInfo.java │ │ ├── AppInfoAdapter.java │ │ ├── FilteredSortedList.java │ │ ├── Intents.java │ │ ├── MainActivity.java │ │ ├── MaterializeApplication.java │ │ ├── MaterializeSharedState.java │ │ ├── SearchMatcher.java │ │ ├── SearchPanelController.java │ │ ├── app │ │ └── ActivityOptionsCompatCompat.java │ │ ├── db │ │ └── Adjustment.java │ │ ├── graphics │ │ ├── CompositeDrawable.java │ │ ├── InfiniteDrawable.java │ │ ├── ShapeDrawable.java │ │ └── TransparencyDrawable.java │ │ ├── io │ │ ├── DrawableGlideMode.java │ │ ├── DrawableStreamFetcher.java │ │ ├── DrawableStreamLoader.java │ │ ├── IconCacheManager.java │ │ ├── IconManager.java │ │ └── PublicIconManager.java │ │ ├── rx │ │ └── RxPackageManager.java │ │ ├── util │ │ ├── DisplayMetricsCompat.java │ │ ├── FilteredSortedListAdapter.java │ │ ├── LauncherUtil.java │ │ ├── SoftInputManager.java │ │ └── UpdateUtil.java │ │ └── widget │ │ └── CompositeView.java │ └── res │ ├── drawable-anydpi-v18 │ ├── stencil_round_back.png │ ├── stencil_round_fore.png │ ├── stencil_round_mask.png │ ├── stencil_square_back.png │ ├── stencil_square_dogear_back.png │ ├── stencil_square_dogear_fore.png │ ├── stencil_square_dogear_mask.png │ ├── stencil_square_fore.png │ └── stencil_square_mask.png │ ├── drawable-hdpi │ ├── stencil_round_back.png │ ├── stencil_round_fore.png │ ├── stencil_round_mask.png │ ├── stencil_square_back.png │ ├── stencil_square_dogear_back.png │ ├── stencil_square_dogear_fore.png │ ├── stencil_square_dogear_mask.png │ ├── stencil_square_fore.png │ └── stencil_square_mask.png │ ├── drawable-mdpi │ ├── stencil_round_back.png │ ├── stencil_round_fore.png │ ├── stencil_round_mask.png │ ├── stencil_square_back.png │ ├── stencil_square_dogear_back.png │ ├── stencil_square_dogear_fore.png │ ├── stencil_square_dogear_mask.png │ ├── stencil_square_fore.png │ └── stencil_square_mask.png │ ├── drawable-nodpi │ └── web_hi_res_512.png │ ├── drawable-xhdpi │ ├── stencil_round_back.png │ ├── stencil_round_fore.png │ ├── stencil_round_mask.png │ ├── stencil_square_back.png │ ├── stencil_square_dogear_back.png │ ├── stencil_square_dogear_fore.png │ ├── stencil_square_dogear_mask.png │ ├── stencil_square_fore.png │ └── stencil_square_mask.png │ ├── drawable-xxhdpi │ ├── stencil_round_back.png │ ├── stencil_round_fore.png │ ├── stencil_round_mask.png │ ├── stencil_square_back.png │ ├── stencil_square_dogear_back.png │ ├── stencil_square_dogear_fore.png │ ├── stencil_square_dogear_mask.png │ ├── stencil_square_fore.png │ └── stencil_square_mask.png │ ├── drawable │ ├── ic_add_24dp.xml │ ├── ic_arrow_forward_24dp.xml │ ├── ic_check_white_24dp.xml │ ├── ic_close_24dp.xml │ ├── ic_filter_list_24dp.xml │ └── ic_more_vert_black_24dp.xml │ ├── layout │ ├── about_activity.xml │ ├── about_header.xml │ ├── about_library_item.xml │ ├── adjust_activity.xml │ ├── main_activity.xml │ ├── main_app_item.xml │ └── search_bar.xml │ ├── menu │ ├── adjust.xml │ ├── main.xml │ └── main_item.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-v16 │ └── styles.xml │ ├── values-zh-rCN │ └── strings.xml │ ├── values-zh-rTW │ └── strings.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screencast.gif └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .gradle 3 | .idea 4 | /local.properties 5 | /build 6 | /captures 7 | *.iml 8 | *.apk 9 | *.jks 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Materialize "靓晒" 2 | ========== 3 | 4 | [![][license badge]](LICENSE) 5 | [![][issues badge]][issues link] 6 | 7 | Materialize all those not material - "乜都靓晒" 8 | 9 | [![Get it on Google Play][play badge]][play link] 10 | 11 | ![](screencast.gif) 12 | 13 | ## Help Translate 14 | 15 | We are looking for people to help us translate this app into different language. 16 | 17 | Join our Transifex project: https://www.transifex.com/oxo/android-materialize/ 18 | 19 | ## Build 20 | 21 | ### Requirements 22 | 23 | - Android SDK Platform 23 24 | - Android Support Repository 24 25 | 26 | ```shell 27 | ./gradlew build 28 | ``` 29 | 30 | ## Third-party libraries used 31 | 32 | - [Android Asset Studio](https://github.com/romannurik/AndroidAssetStudio) 33 | 34 | ## License 35 | 36 | [GNU General Public License, version 3](LICENSE) 37 | 38 | [play badge]: https://developer.android.com/images/brand/en_generic_rgb_wo_45.png 39 | [play link]: https://play.google.com/store/apps/details?id=ooo.oxo.apps.materialize 40 | 41 | [license badge]: https://img.shields.io/github/license/oxoooo/materialize.svg?style=flat-square 42 | 43 | [issues badge]: https://img.shields.io/github/issues/oxoooo/materialize.svg?style=flat-square 44 | [issues link]: https://github.com/oxoooo/materialize/issues 45 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /gradle.properties 3 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | apply plugin: 'com.android.application' 20 | apply plugin: 'me.tatarka.retrolambda' 21 | 22 | def gitSha = 'git rev-parse --short HEAD'.execute([], project.rootDir).text.trim() 23 | def gitTag = 'git tag'.execute([], project.rootDir).text.trim().split("\n").last() 24 | def gitCommits = Integer.parseInt('git rev-list --count HEAD'.execute([], project.rootDir).text.trim()) 25 | 26 | android { 27 | compileSdkVersion 23 28 | buildToolsVersion '23.0.2' 29 | 30 | defaultConfig { 31 | applicationId "ooo.oxo.apps.materialize" 32 | 33 | minSdkVersion 15 34 | 35 | targetSdkVersion 23 36 | 37 | versionCode 20000 + gitCommits 38 | versionName gitTag 39 | 40 | manifestPlaceholders = [APP_NAME: '@string/app_name'] 41 | 42 | // Versioning 43 | buildConfigField "String", "GIT_SHA", "\"${gitSha}\"" 44 | println "Building ${gitTag} (rev. ${gitCommits} on ${gitSha})" 45 | 46 | // FIR 47 | buildConfigField "boolean", "FIR_ENABLED", "!DEBUG && ${project.hasProperty('FIR_API_TOKEN')}" 48 | buildConfigField "String", "FIR_API_TOKEN", 49 | project.hasProperty('FIR_API_TOKEN') ? "\"${FIR_API_TOKEN}\"" : "null" 50 | 51 | buildConfigField "boolean", "FIR_OTA_ENABLED", "FIR_ENABLED" 52 | } 53 | 54 | dataBinding { 55 | enabled = true 56 | } 57 | 58 | compileOptions { 59 | sourceCompatibility JavaVersion.VERSION_1_8 60 | targetCompatibility JavaVersion.VERSION_1_8 61 | } 62 | 63 | packagingOptions { 64 | exclude 'META-INF/services/javax.annotation.processing.Processor' 65 | } 66 | 67 | if (project.hasProperty('STOREFILE')) { 68 | signingConfigs { 69 | release { 70 | storeFile file(STOREFILE) 71 | storePassword STOREPASS 72 | keyAlias KEYALIAS 73 | keyPassword KEYPASS 74 | } 75 | } 76 | } 77 | 78 | buildTypes { 79 | debug { 80 | applicationIdSuffix ".debug" 81 | manifestPlaceholders = [APP_NAME: '@string/app_name_debug'] 82 | } 83 | 84 | release { 85 | minifyEnabled true 86 | shrinkResources true 87 | 88 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 89 | 90 | if (project.hasProperty('STOREFILE')) { 91 | println "Using release keystore ${signingConfigs.release.storeFile}" 92 | signingConfig signingConfigs.release 93 | } else { 94 | println "Using default key" 95 | } 96 | } 97 | } 98 | 99 | productFlavors { 100 | github { 101 | manifestPlaceholders = [UMENG_CHANNEL: "GitHub"] 102 | } 103 | 104 | fir { 105 | manifestPlaceholders = [UMENG_CHANNEL: "FIR"] 106 | } 107 | 108 | google { 109 | manifestPlaceholders = [UMENG_CHANNEL: "Google"] 110 | buildConfigField "boolean", "FIR_OTA_ENABLED", "false" 111 | } 112 | 113 | wandoujia { 114 | manifestPlaceholders = [UMENG_CHANNEL: "Wandoujia"] 115 | } 116 | 117 | coolapk { 118 | manifestPlaceholders = [UMENG_CHANNEL: "CookApk"] 119 | } 120 | 121 | baidu { 122 | manifestPlaceholders = [UMENG_CHANNEL: "Baidu"] 123 | buildConfigField "boolean", "FIR_OTA_ENABLED", "false" 124 | } 125 | 126 | tencent { 127 | manifestPlaceholders = [UMENG_CHANNEL: "Tencent"] 128 | } 129 | 130 | qihoo { 131 | manifestPlaceholders = [UMENG_CHANNEL: "360"] 132 | } 133 | } 134 | 135 | applicationVariants.all { variant -> 136 | variant.outputs.each { output -> 137 | if (output.outputFile != null && output.outputFile.name.endsWith('.apk')) { 138 | output.outputFile = file("${output.outputFile.parent}/materialize" + 139 | "-${variant.buildType.name.toLowerCase()}" + 140 | "-${variant.versionName}" + 141 | "-${variant.flavorName.toLowerCase()}" + 142 | ".apk") 143 | } 144 | } 145 | } 146 | } 147 | 148 | dependencies { 149 | compile 'com.android.support:design:23.1.1' 150 | compile 'com.android.support:cardview-v7:23.1.1' 151 | compile 'com.android.support:recyclerview-v7:23.1.1' 152 | 153 | compile 'com.squareup.okhttp:okhttp:2.5.0' 154 | 155 | compile 'com.github.bumptech.glide:glide:3.6.1' 156 | 157 | compile 'io.reactivex:rxandroid:1.0.1' 158 | 159 | compile 'com.trello:rxlifecycle:0.3.0' 160 | compile 'com.trello:rxlifecycle-components:0.3.0' 161 | 162 | compile 'com.jakewharton.rxbinding:rxbinding-support-v4:0.3.0' 163 | compile 'com.jakewharton.rxbinding:rxbinding-appcompat-v7:0.3.0' 164 | compile 'com.jakewharton.rxbinding:rxbinding-design:0.3.0' 165 | compile 'com.jakewharton.rxbinding:rxbinding-recyclerview-v7:0.3.0' 166 | 167 | compile 'com.tbruyelle.rxpermissions:rxpermissions:0.4.4@aar' 168 | 169 | compile 'io.realm:realm-android:0.85.1' 170 | 171 | compile 'com.github.oxoooo:data-binding-support:1.1.0' 172 | 173 | compile 'com.github.stuxuhai:jpinyin:1.0' 174 | 175 | compile 'com.umeng.analytics:analytics:latest.integration' 176 | 177 | compile 'im.fir:sdk:latest.integration@aar' 178 | } 179 | -------------------------------------------------------------------------------- /app/gradle.properties: -------------------------------------------------------------------------------- 1 | FIR_API_TOKEN = b2d484fb070361b8bbf067132cd2954d 2 | 3 | STOREFILE = release.jks 4 | STOREPASS = oxooxo 5 | KEYALIAS = android 6 | KEYPASS = oxooxo 7 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keepattributes LineNumberTable 2 | 3 | # retrolambda 4 | -dontwarn java.lang.invoke.* 5 | 6 | # okhttp 7 | -dontwarn okio.** 8 | 9 | # retrofit 10 | -dontwarn retrofit.** 11 | -keep class retrofit.** { *; } 12 | -keepattributes Signature 13 | -keepattributes Exceptions 14 | 15 | # rx 16 | -dontwarn rx.** 17 | -keepclassmembers class rx.** { *; } 18 | 19 | # support library 20 | -keep class android.support.v7.widget.LinearLayoutManager { *; } 21 | 22 | # data binding 23 | -keep class ooo.oxo.apps.materialize.databinding.** { *; } 24 | 25 | # glide 26 | -keep class ooo.oxo.apps.materialize.io.DrawableGlideMode { *; } 27 | 28 | # realm 29 | -keep class io.realm.annotations.RealmModule 30 | -keep @io.realm.annotations.RealmModule class * 31 | -keep class io.realm.internal.Keep 32 | -keep @io.realm.internal.Keep class * 33 | -dontwarn javax.** 34 | -dontwarn io.realm.** 35 | 36 | # all in all 37 | -keepnames class * { *; } 38 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 39 | 40 | 43 | 44 | 47 | 48 | 51 | 52 | 55 | 56 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/AboutActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize; 20 | 21 | import android.content.Intent; 22 | import android.databinding.DataBindingUtil; 23 | import android.net.Uri; 24 | import android.os.Bundle; 25 | import android.support.v4.util.ArrayMap; 26 | import android.support.v7.app.AppCompatActivity; 27 | import android.support.v7.widget.RecyclerView; 28 | import android.view.LayoutInflater; 29 | import android.view.ViewGroup; 30 | 31 | import ooo.oxo.apps.materialize.databinding.AboutActivityBinding; 32 | import ooo.oxo.apps.materialize.databinding.AboutHeaderBinding; 33 | import ooo.oxo.apps.materialize.databinding.AboutLibraryItemBinding; 34 | import ooo.oxo.library.databinding.support.widget.BindingRecyclerView; 35 | 36 | public class AboutActivity extends AppCompatActivity { 37 | 38 | private final ArrayMap libraries = new ArrayMap<>(); 39 | 40 | @Override 41 | @SuppressWarnings("SpellCheckingInspection") 42 | protected void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | 45 | AboutActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.about_activity); 46 | 47 | binding.toolbar.setNavigationOnClickListener(v -> supportFinishAfterTransition()); 48 | 49 | libraries.put("romannurik / AndroidAssetStudio", "https://github.com/romannurik/AndroidAssetStudio"); 50 | 51 | binding.libraries.setAdapter(new LibrariesAdapter()); 52 | } 53 | 54 | private void open(String url) { 55 | Intent intent = new Intent(Intent.ACTION_VIEW); 56 | intent.setData(Uri.parse(url)); 57 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 58 | startActivity(intent); 59 | } 60 | 61 | class LibrariesAdapter extends RecyclerView.Adapter { 62 | 63 | private final LayoutInflater inflater = getLayoutInflater(); 64 | 65 | @Override 66 | public BindingRecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 67 | return viewType == 0 68 | ? new HeaderViewHolder(AboutHeaderBinding.inflate(inflater, parent, false)) 69 | : new ItemViewHolder(AboutLibraryItemBinding.inflate(inflater, parent, false)); 70 | } 71 | 72 | @Override 73 | public void onBindViewHolder(BindingRecyclerView.ViewHolder holder, int position) { 74 | if (holder.getItemViewType() == 0) { 75 | ((HeaderViewHolder) holder).binding.setName(position == 0 76 | ? R.string.fork_me_on_github 77 | : R.string.libraries_used); 78 | } else { 79 | ItemViewHolder itemHolder = (ItemViewHolder) holder; 80 | if (position == 1) { 81 | itemHolder.binding.setName("oxoooo / materialize"); 82 | } else { 83 | itemHolder.binding.setName(libraries.keyAt(position - 3)); 84 | } 85 | } 86 | } 87 | 88 | @Override 89 | public int getItemViewType(int position) { 90 | return position == 0 || position == 2 ? 0 : 1; 91 | } 92 | 93 | @Override 94 | public int getItemCount() { 95 | return libraries.size() + 3; 96 | } 97 | 98 | private void handleItemClick(int position) { 99 | if (position == 1) { 100 | open("https://github.com/oxoooo/materialize"); 101 | } else { 102 | open(libraries.valueAt(position - 3)); 103 | } 104 | } 105 | 106 | class HeaderViewHolder extends BindingRecyclerView.ViewHolder { 107 | 108 | public HeaderViewHolder(AboutHeaderBinding binding) { 109 | super(binding); 110 | } 111 | 112 | } 113 | 114 | class ItemViewHolder extends BindingRecyclerView.ViewHolder { 115 | 116 | public ItemViewHolder(AboutLibraryItemBinding binding) { 117 | super(binding); 118 | itemView.setOnClickListener(v -> handleItemClick(getAdapterPosition())); 119 | } 120 | 121 | } 122 | 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/AdjustActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize; 20 | 21 | import android.Manifest; 22 | import android.content.Intent; 23 | import android.content.pm.ActivityInfo; 24 | import android.databinding.DataBindingUtil; 25 | import android.graphics.Bitmap; 26 | import android.graphics.Canvas; 27 | import android.os.Build; 28 | import android.os.Bundle; 29 | import android.support.annotation.IdRes; 30 | import android.support.v7.widget.PopupMenu; 31 | import android.view.Menu; 32 | import android.widget.RadioButton; 33 | import android.widget.RadioGroup; 34 | import android.widget.Toast; 35 | 36 | import com.jakewharton.rxbinding.view.RxMenuItem; 37 | import com.jakewharton.rxbinding.view.RxView; 38 | import com.tbruyelle.rxpermissions.RxPermissions; 39 | import com.trello.rxlifecycle.components.support.RxAppCompatActivity; 40 | import com.umeng.analytics.MobclickAgent; 41 | 42 | import java.util.HashMap; 43 | 44 | import io.realm.Realm; 45 | import ooo.oxo.apps.materialize.databinding.AdjustActivityBinding; 46 | import ooo.oxo.apps.materialize.db.Adjustment; 47 | import ooo.oxo.apps.materialize.graphics.CompositeDrawable; 48 | import ooo.oxo.apps.materialize.graphics.InfiniteDrawable; 49 | import ooo.oxo.apps.materialize.graphics.ShapeDrawable; 50 | import ooo.oxo.apps.materialize.graphics.TransparencyDrawable; 51 | import ooo.oxo.apps.materialize.io.IconCacheManager; 52 | import ooo.oxo.apps.materialize.io.PublicIconManager; 53 | import ooo.oxo.apps.materialize.util.LauncherUtil; 54 | import rx.Observable; 55 | import rx.android.schedulers.AndroidSchedulers; 56 | import rx.schedulers.Schedulers; 57 | 58 | public class AdjustActivity extends RxAppCompatActivity { 59 | 60 | private static final boolean SUPPORT_MIPMAP = Build.VERSION.SDK_INT >= 18; 61 | 62 | /** 63 | * Icon size in pixel since Android 4.3 (18) with mipmaps support 64 | * It's the actual size of drawables in drawable-anydpi-v18 folder 65 | */ 66 | private static final int LAUNCHER_SIZE_MIPMAP = 192; 67 | 68 | private int index; 69 | 70 | private AdjustActivityBinding binding; 71 | 72 | private IconCacheManager iconCacheManager; 73 | 74 | private PublicIconManager publicIconManager; 75 | 76 | private AdjustViewModel viewModel = new AdjustViewModel(); 77 | 78 | private Realm realm; 79 | 80 | @Override 81 | protected void onCreate(Bundle savedInstanceState) { 82 | super.onCreate(savedInstanceState); 83 | 84 | index = getIntent().getIntExtra("index", 0); 85 | 86 | binding = DataBindingUtil.setContentView(this, R.layout.adjust_activity); 87 | 88 | binding.setAdjust(viewModel); 89 | 90 | binding.setTransparency(new TransparencyDrawable( 91 | getResources(), R.dimen.transparency_grid_size)); 92 | 93 | RadioGroup shapes = binding.shape; 94 | 95 | for (int i = 0; i < shapes.getChildCount(); i++) { 96 | RadioButton child = (RadioButton) shapes.getChildAt(i); 97 | CompositeDrawable.Shape shape = viewModel.mapShape(child.getId()); 98 | child.setButtonDrawable(new ShapeDrawable(getResources(), shape, R.color.accent)); 99 | child.setBackgroundDrawable(null); 100 | } 101 | 102 | PopupMenu popup = new PopupMenu(this, binding.more); 103 | popup.inflate(R.menu.adjust); 104 | 105 | Menu menu = popup.getMenu(); 106 | 107 | binding.more.setOnClickListener(v -> popup.show()); 108 | 109 | iconCacheManager = new IconCacheManager(this); 110 | 111 | publicIconManager = new PublicIconManager(this); 112 | 113 | ActivityInfo activity = getIntent().getParcelableExtra("activity"); 114 | 115 | Observable resolving = Observable.just(activity) 116 | .compose(bindToLifecycle()) 117 | .observeOn(Schedulers.io()) 118 | .map(act -> AppInfo.from(act, getPackageManager())) 119 | .filter(app -> app != null) 120 | .filter(AppInfo::resolveIcon) 121 | .cache(); 122 | 123 | resolving 124 | .observeOn(AndroidSchedulers.mainThread()) 125 | .subscribe(binding::setApp); 126 | 127 | Observable infinity = resolving 128 | .compose(bindToLifecycle()) 129 | .observeOn(Schedulers.computation()) 130 | .map(app -> InfiniteDrawable.from(app.icon)) 131 | .filter(drawable -> drawable != null) 132 | .cache(); 133 | 134 | infinity 135 | .observeOn(AndroidSchedulers.mainThread()) 136 | .subscribe(viewModel::setInfinite); 137 | 138 | realm = Realm.getInstance(this); 139 | 140 | Observable adjustment = resolving 141 | .compose(bindToLifecycle()) 142 | .observeOn(AndroidSchedulers.mainThread()) 143 | .map(app -> realm.where(Adjustment.class) 144 | .equalTo("component", app.component.flattenToString()) 145 | .findFirst()) 146 | .cache(); 147 | 148 | adjustment.map(model -> model == null) 149 | .doOnNext(binding::setIsNew) 150 | .map(isNew -> !isNew) 151 | .subscribe(RxMenuItem.visible(menu.findItem(R.id.re_add_to_home))); 152 | 153 | adjustment.filter(model -> model != null) 154 | .zipWith(infinity, (model, drawable) -> model) 155 | .observeOn(AndroidSchedulers.mainThread()) 156 | .subscribe(viewModel::applyFromModel); 157 | 158 | RxView.clicks(binding.cancel) 159 | .compose(bindToLifecycle()) 160 | .subscribe(avoid -> { 161 | finishWithResult(RESULT_CANCELED); 162 | }); 163 | 164 | int size = SUPPORT_MIPMAP ? LAUNCHER_SIZE_MIPMAP 165 | : getResources().getDimensionPixelSize(R.dimen.launcher_size); 166 | 167 | Observable renders = Observable.just(binding.result.getComposite()) 168 | .compose(bindToLifecycle()) 169 | .observeOn(Schedulers.computation()) 170 | .map(compose -> { 171 | Bitmap icon = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); 172 | compose.drawTo(new Canvas(icon), SUPPORT_MIPMAP); 173 | return icon; 174 | }) 175 | .observeOn(Schedulers.io()) 176 | .zipWith(resolving, (icon, app) -> { 177 | iconCacheManager.save(app, icon); 178 | return icon; 179 | }); 180 | 181 | Observable persist = adjustment 182 | .compose(bindToLifecycle()) 183 | .observeOn(AndroidSchedulers.mainThread()) 184 | .zipWith(resolving, (model, app) -> { 185 | realm.beginTransaction(); 186 | 187 | if (model == null || !model.isValid()) { 188 | model = realm.createObject(Adjustment.class); 189 | model.setComponent(app.component.flattenToString()); 190 | } 191 | 192 | model.setShape(viewModel.getShapeModelValue()); 193 | model.setPadding(viewModel.getPadding()); 194 | model.setColor(viewModel.getBackgroundModelValue()); 195 | 196 | realm.commitTransaction(); 197 | 198 | return model; 199 | }); 200 | 201 | RxView.clicks(binding.save) 202 | .compose(bindToLifecycle()) 203 | .zipWith(resolving, (avoid, app) -> app) 204 | .flatMap(avoid -> Observable.zip(renders, persist, (icon, ad) -> icon)) 205 | .observeOn(AndroidSchedulers.mainThread()) 206 | .subscribe(avoid -> { 207 | Toast.makeText(this, R.string.toast_saved, Toast.LENGTH_SHORT).show(); 208 | MobclickAgent.onEvent(this, "compose", makeEvent("none")); 209 | finishWithResult(RESULT_OK); 210 | }); 211 | 212 | Observable.merge(RxView.clicks(binding.install), RxMenuItem.clicks(menu.findItem(R.id.re_add_to_home))) 213 | .compose(bindToLifecycle()) 214 | .zipWith(resolving, (avoid, app) -> app) 215 | .flatMap(avoid -> Observable.zip(renders, persist, (icon, ad) -> icon)) 216 | .observeOn(AndroidSchedulers.mainThread()) 217 | .zipWith(resolving, (icon, app) -> { 218 | LauncherUtil.installShortcut(this, app.getIntent(), app.label, icon); 219 | return null; 220 | }) 221 | .subscribe(avoid -> { 222 | Toast.makeText(this, R.string.toast_added_to_home, Toast.LENGTH_SHORT).show(); 223 | MobclickAgent.onEvent(this, "compose", makeEvent("launcher")); 224 | MobclickAgent.onEvent(this, "install"); 225 | finishWithResult(RESULT_OK); 226 | }); 227 | 228 | Observable permission = RxPermissions 229 | .getInstance(this) 230 | .request(Manifest.permission.WRITE_EXTERNAL_STORAGE) 231 | .doOnNext(RxMenuItem.enabled(menu.findItem(R.id.export_to_gallery))) 232 | .filter(granted -> granted); 233 | 234 | RxMenuItem.clicks(menu.findItem(R.id.export_to_gallery)) 235 | .compose(bindToLifecycle()) 236 | .zipWith(resolving, (avoid, app) -> app) 237 | .flatMap(avoid -> Observable.zip(renders, persist, (icon, ad) -> icon)) 238 | .observeOn(AndroidSchedulers.mainThread()) 239 | .zipWith(permission, (icon, granted) -> icon) 240 | .observeOn(Schedulers.io()) 241 | .zipWith(resolving, (icon, app) -> { 242 | publicIconManager.save(app, icon); 243 | return null; 244 | }) 245 | .observeOn(AndroidSchedulers.mainThread()) 246 | .subscribe(avoid -> { 247 | Toast.makeText(this, R.string.toast_exported_to_gallery, Toast.LENGTH_SHORT).show(); 248 | MobclickAgent.onEvent(this, "compose", makeEvent("gallery")); 249 | finishWithResult(RESULT_OK); 250 | }); 251 | 252 | Observable deleteCache = resolving 253 | .compose(bindToLifecycle()) 254 | .observeOn(Schedulers.io()) 255 | .doOnNext(iconCacheManager::delete); 256 | 257 | Observable deletePersist = adjustment 258 | .compose(bindToLifecycle()) 259 | .observeOn(AndroidSchedulers.mainThread()) 260 | .doOnNext(model -> { 261 | if (model != null) { 262 | realm.beginTransaction(); 263 | model.removeFromRealm(); 264 | realm.commitTransaction(); 265 | } 266 | }); 267 | 268 | RxMenuItem.clicks(menu.findItem(R.id.reset)) 269 | .compose(bindToLifecycle()) 270 | .zipWith(resolving, (avoid, app) -> app) 271 | .flatMap(avoid -> Observable.zip(deleteCache, deletePersist, (a, b) -> null)) 272 | .doOnNext(avoid -> viewModel.reset()) 273 | .subscribe(avoid -> { 274 | MobclickAgent.onEvent(this, "reset"); 275 | finishWithResult(RESULT_CANCELED); 276 | }); 277 | } 278 | 279 | private void finishWithResult(int resultCode) { 280 | setResult(resultCode, new Intent().putExtra("index", index)); 281 | supportFinishAfterTransition(); 282 | } 283 | 284 | @Override 285 | protected void onResume() { 286 | super.onResume(); 287 | MobclickAgent.onResume(this); 288 | } 289 | 290 | @Override 291 | protected void onPause() { 292 | super.onPause(); 293 | MobclickAgent.onPause(this); 294 | } 295 | 296 | private HashMap makeEvent(String usage) { 297 | HashMap event = new HashMap<>(); 298 | event.put("shape", viewModel.getShape().name()); 299 | event.put("color", mapColorName(binding.colors.getCheckedRadioButtonId())); 300 | event.put("usage", usage); 301 | return event; 302 | } 303 | 304 | private String mapColorName(@IdRes int radio) { 305 | switch (radio) { 306 | case R.id.color_white: 307 | return "white"; 308 | case R.id.color_infinite: 309 | return "infinite"; 310 | default: 311 | return null; 312 | } 313 | } 314 | 315 | } 316 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/AdjustViewModel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize; 20 | 21 | import android.databinding.BaseObservable; 22 | import android.databinding.Bindable; 23 | import android.databinding.adapters.SeekBarBindingAdapter; 24 | import android.graphics.Color; 25 | import android.graphics.drawable.ColorDrawable; 26 | import android.graphics.drawable.Drawable; 27 | import android.support.annotation.IdRes; 28 | import android.view.View; 29 | import android.widget.RadioGroup; 30 | 31 | import ooo.oxo.apps.materialize.db.Adjustment; 32 | import ooo.oxo.apps.materialize.graphics.CompositeDrawable; 33 | import ooo.oxo.apps.materialize.graphics.InfiniteDrawable; 34 | 35 | public class AdjustViewModel extends BaseObservable { 36 | 37 | private ColorDrawable white = new ColorDrawable(Color.WHITE); 38 | 39 | private InfiniteDrawable infinite; 40 | 41 | private CompositeDrawable.Shape shape; 42 | 43 | private float padding; 44 | 45 | private Drawable background; 46 | 47 | public AdjustViewModel() { 48 | reset(); 49 | } 50 | 51 | public void reset() { 52 | setShape(CompositeDrawable.Shape.SQUARE); 53 | setPadding(0); 54 | setBackground(white); 55 | } 56 | 57 | public void applyFromModel(Adjustment model) { 58 | setShape(mapShapeFromModel(model.getShape())); 59 | setPadding(model.getPadding()); 60 | setBackground(mapColorFromModel(model.getColor())); 61 | } 62 | 63 | @Bindable 64 | public ColorDrawable getWhite() { 65 | return white; 66 | } 67 | 68 | @Bindable 69 | public InfiniteDrawable getInfinite() { 70 | return infinite; 71 | } 72 | 73 | public void setInfinite(InfiniteDrawable infinite) { 74 | this.infinite = infinite; 75 | notifyPropertyChanged(ooo.oxo.apps.materialize.BR.infinite); 76 | } 77 | 78 | @Bindable 79 | public CompositeDrawable.Shape getShape() { 80 | return shape; 81 | } 82 | 83 | public void setShape(CompositeDrawable.Shape shape) { 84 | this.shape = shape; 85 | notifyPropertyChanged(ooo.oxo.apps.materialize.BR.shape); 86 | notifyPropertyChanged(ooo.oxo.apps.materialize.BR.shapeRadioId); 87 | } 88 | 89 | @Bindable 90 | public RadioGroup.OnCheckedChangeListener getShapeWatcher() { 91 | return (group, checkedId) -> setShape(mapShape(checkedId)); 92 | } 93 | 94 | @IdRes 95 | @Bindable 96 | public int getShapeRadioId() { 97 | return mapShapeRadioId(shape); 98 | } 99 | 100 | @Adjustment.Shape 101 | public int getShapeModelValue() { 102 | return mapShapeModelValue(shape); 103 | } 104 | 105 | @Bindable 106 | public float getPadding() { 107 | return padding; 108 | } 109 | 110 | public void setPadding(float padding) { 111 | this.padding = padding; 112 | notifyPropertyChanged(ooo.oxo.apps.materialize.BR.padding); 113 | notifyPropertyChanged(ooo.oxo.apps.materialize.BR.paddingValue); 114 | 115 | if (infinite != null) { 116 | infinite.setPadding(padding); 117 | } 118 | } 119 | 120 | @Bindable 121 | public int getPaddingMax() { 122 | return 40 * 2 * 100; // TODO: use dimens 123 | } 124 | 125 | @Bindable 126 | public int getPaddingValue() { 127 | return (40 + (int) padding) * 100; 128 | } 129 | 130 | @Bindable 131 | public SeekBarBindingAdapter.OnProgressChanged getPaddingWatcher() { 132 | return (seekBar, progress, fromUser) -> { 133 | if (fromUser) { 134 | setPadding((progress - seekBar.getMax() / 2f) / 100f); 135 | } 136 | }; 137 | } 138 | 139 | @Bindable 140 | public Drawable getBackground() { 141 | return background; 142 | } 143 | 144 | public void setBackground(Drawable background) { 145 | this.background = background; 146 | notifyPropertyChanged(ooo.oxo.apps.materialize.BR.background); 147 | notifyPropertyChanged(ooo.oxo.apps.materialize.BR.backgroundRadioId); 148 | } 149 | 150 | @Bindable 151 | public RadioGroup.OnCheckedChangeListener getBackgroundWatcher() { 152 | return (group, checkedId) -> setBackground(mapColor(checkedId)); 153 | } 154 | 155 | @IdRes 156 | @Bindable 157 | public int getBackgroundRadioId() { 158 | return mapColorRadioId(background); 159 | } 160 | 161 | @Adjustment.Color 162 | public int getBackgroundModelValue() { 163 | return mapColorModelValue(background); 164 | } 165 | 166 | public CompositeDrawable.Shape mapShape(@IdRes int radio) { 167 | switch (radio) { 168 | case R.id.shape_square: 169 | return CompositeDrawable.Shape.SQUARE; 170 | case R.id.shape_square_score: 171 | return CompositeDrawable.Shape.SQUARE_SCORE; 172 | case R.id.shape_square_dog_ear: 173 | return CompositeDrawable.Shape.SQUARE_DOGEAR; 174 | case R.id.shape_round: 175 | return CompositeDrawable.Shape.ROUND; 176 | case R.id.shape_round_score: 177 | return CompositeDrawable.Shape.ROUND_SCORE; 178 | default: 179 | return null; 180 | } 181 | } 182 | 183 | public CompositeDrawable.Shape mapShapeFromModel(@Adjustment.Shape int shape) { 184 | switch (shape) { 185 | case Adjustment.SHAPE_SQUARE: 186 | return CompositeDrawable.Shape.SQUARE; 187 | case Adjustment.SHAPE_SQUARE_SCORE: 188 | return CompositeDrawable.Shape.SQUARE_SCORE; 189 | case Adjustment.SHAPE_SQUARE_DOGEAR: 190 | return CompositeDrawable.Shape.SQUARE_DOGEAR; 191 | case Adjustment.SHAPE_ROUND: 192 | return CompositeDrawable.Shape.ROUND; 193 | case Adjustment.SHAPE_ROUND_SCORE: 194 | return CompositeDrawable.Shape.ROUND_SCORE; 195 | default: 196 | return null; 197 | } 198 | } 199 | 200 | @IdRes 201 | public int mapShapeRadioId(CompositeDrawable.Shape shape) { 202 | switch (shape) { 203 | case SQUARE: 204 | return R.id.shape_square; 205 | case SQUARE_SCORE: 206 | return R.id.shape_square_score; 207 | case SQUARE_DOGEAR: 208 | return R.id.shape_square_dog_ear; 209 | case ROUND: 210 | return R.id.shape_round; 211 | case ROUND_SCORE: 212 | return R.id.shape_round_score; 213 | default: 214 | return View.NO_ID; 215 | } 216 | } 217 | 218 | @Adjustment.Shape 219 | public int mapShapeModelValue(CompositeDrawable.Shape shape) { 220 | switch (shape) { 221 | case SQUARE: 222 | return Adjustment.SHAPE_SQUARE; 223 | case SQUARE_SCORE: 224 | return Adjustment.SHAPE_SQUARE_SCORE; 225 | case SQUARE_DOGEAR: 226 | return Adjustment.SHAPE_SQUARE_DOGEAR; 227 | case ROUND: 228 | return Adjustment.SHAPE_ROUND; 229 | case ROUND_SCORE: 230 | return Adjustment.SHAPE_ROUND_SCORE; 231 | default: 232 | throw new IllegalArgumentException(); 233 | } 234 | } 235 | 236 | public Drawable mapColor(@IdRes int radio) { 237 | switch (radio) { 238 | case R.id.color_white: 239 | return white; 240 | case R.id.color_infinite: 241 | return infinite; 242 | default: 243 | return null; 244 | } 245 | } 246 | 247 | public Drawable mapColorFromModel(@Adjustment.Color int color) { 248 | switch (color) { 249 | case Adjustment.COLOR_WHITE: 250 | return white; 251 | case Adjustment.COLOR_INFINITE: 252 | return infinite; 253 | default: 254 | return null; 255 | } 256 | } 257 | 258 | @IdRes 259 | public int mapColorRadioId(Drawable color) { 260 | if (color == white) { 261 | return R.id.color_white; 262 | } else if (color == infinite) { 263 | return R.id.color_infinite; 264 | } else { 265 | return View.NO_ID; 266 | } 267 | } 268 | 269 | @Adjustment.Color 270 | public int mapColorModelValue(Drawable color) { 271 | if (color == white) { 272 | return Adjustment.COLOR_WHITE; 273 | } else if (color == infinite) { 274 | return Adjustment.COLOR_INFINITE; 275 | } else { 276 | throw new IllegalArgumentException(); 277 | } 278 | } 279 | 280 | } 281 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/AppInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize; 20 | 21 | import android.content.ComponentName; 22 | import android.content.Intent; 23 | import android.content.pm.ActivityInfo; 24 | import android.content.pm.PackageManager; 25 | import android.content.res.Resources; 26 | import android.graphics.Bitmap; 27 | import android.graphics.BitmapFactory; 28 | import android.net.Uri; 29 | import android.support.annotation.Nullable; 30 | import android.text.TextUtils; 31 | import android.util.Log; 32 | import android.util.TypedValue; 33 | 34 | import com.github.stuxuhai.jpinyin.PinyinFormat; 35 | import com.github.stuxuhai.jpinyin.PinyinHelper; 36 | 37 | import ooo.oxo.apps.materialize.io.IconCacheManager; 38 | import ooo.oxo.apps.materialize.util.DisplayMetricsCompat; 39 | 40 | /** 41 | * A wrapper of {@link ActivityInfo} 42 | */ 43 | public class AppInfo { 44 | 45 | private static final String TAG = "AppInfo"; 46 | 47 | private static int[] DENSITIES = new int[]{ 48 | DisplayMetricsCompat.DENSITY_XXXHIGH, 49 | DisplayMetricsCompat.DENSITY_XXHIGH, 50 | DisplayMetricsCompat.DENSITY_XHIGH, 51 | DisplayMetricsCompat.DENSITY_HIGH // 这都没有狗带吧 52 | }; 53 | 54 | public final ActivityInfo activityInfo; 55 | 56 | public ComponentName component; 57 | 58 | public String label; 59 | 60 | public Pinyin labelPinyin; 61 | 62 | public Resources res; 63 | 64 | public int iconResId; 65 | 66 | public TypedValue iconValue = new TypedValue(); 67 | 68 | public Bitmap icon = null; 69 | 70 | public Uri cache = null; 71 | 72 | private AppInfo(ActivityInfo activityInfo) { 73 | this.activityInfo = activityInfo; 74 | } 75 | 76 | /** 77 | * Wraps and resolve an {@link ActivityInfo} 78 | * 79 | * @param activityInfo The {@link ActivityInfo} object to resolve 80 | * @param packageManager A {@link PackageManager} instance to resolve the {@link ActivityInfo} 81 | * @return An {@link AppInfo} instance with its {@link #label} and icon resolved 82 | */ 83 | @Nullable 84 | public static AppInfo from(ActivityInfo activityInfo, PackageManager packageManager) { 85 | AppInfo app = new AppInfo(activityInfo); 86 | return app.resolve(packageManager) ? app : null; 87 | } 88 | 89 | @Nullable 90 | public static AppInfo from(ActivityInfo activityInfo, PackageManager packageManager, IconCacheManager iconCacheManager) { 91 | AppInfo app = from(activityInfo, packageManager); 92 | 93 | if (app != null) { 94 | app.resolveCache(iconCacheManager); 95 | } 96 | 97 | return app; 98 | } 99 | 100 | public boolean resolve(PackageManager packageManager) { 101 | component = new ComponentName(activityInfo.packageName, activityInfo.name); 102 | 103 | label = activityInfo.loadLabel(packageManager).toString(); 104 | labelPinyin = Pinyin.from(label); 105 | 106 | String app = activityInfo.applicationInfo.packageName; 107 | 108 | try { 109 | res = packageManager.getResourcesForApplication(activityInfo.applicationInfo); 110 | } catch (PackageManager.NameNotFoundException e) { 111 | Log.e(TAG, "Failed to get resources from " + app, e); 112 | return false; 113 | } 114 | 115 | iconResId = activityInfo.getIconResource(); 116 | 117 | if (iconResId == 0) { 118 | Log.e(TAG, "No icon found in " + app); 119 | return false; 120 | } 121 | 122 | if (!resolveIconValue()) { 123 | Log.e(TAG, "Failed to resolve icon drawable for " + app); 124 | return false; 125 | } 126 | 127 | return true; 128 | } 129 | 130 | private boolean resolveIconValue() { 131 | for (int density : DENSITIES) { 132 | try { 133 | res.getValueForDensity(iconResId, density, iconValue, true); 134 | return true; 135 | } catch (Exception ignored) { 136 | } 137 | } 138 | 139 | return false; 140 | } 141 | 142 | public boolean resolveIcon() { 143 | if (iconResId == 0) { 144 | return false; 145 | } 146 | 147 | icon = BitmapFactory.decodeStream(res.openRawResource(iconResId, iconValue)); 148 | 149 | return icon != null; 150 | } 151 | 152 | public boolean resolveCache(IconCacheManager iconCacheManager) { 153 | cache = iconCacheManager.get(this); 154 | return cache != null; 155 | } 156 | 157 | public Intent getIntent() { 158 | return new Intent(Intent.ACTION_MAIN) 159 | .putExtra("__materialize_nonce__", System.currentTimeMillis()) 160 | .setComponent(component) 161 | .setFlags(activityInfo.flags); 162 | } 163 | 164 | @Override 165 | public String toString() { 166 | return "AppInfo{" + (component == null ? "(not resolved)" : component.flattenToShortString()) + "}"; 167 | } 168 | 169 | public static class Pinyin { 170 | 171 | public final String pinyinLong; 172 | 173 | public final String pinyinShort; 174 | 175 | private Pinyin(String[] source) { 176 | StringBuilder builderLong = new StringBuilder(); 177 | StringBuilder builderShort = new StringBuilder(); 178 | 179 | for (String s : source) { 180 | s = s.trim(); 181 | if (TextUtils.isGraphic(s)) { 182 | builderLong.append(s); 183 | builderShort.append(s.charAt(0)); 184 | } 185 | } 186 | 187 | this.pinyinLong = builderLong.toString(); 188 | this.pinyinShort = builderShort.toString(); 189 | } 190 | 191 | public static Pinyin from(String source) { 192 | return new Pinyin(PinyinHelper.convertToPinyinString(source, " ", PinyinFormat.WITHOUT_TONE) 193 | .toLowerCase() 194 | .split(" ")); 195 | } 196 | 197 | } 198 | 199 | } 200 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/AppInfoAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize; 20 | 21 | import android.content.Context; 22 | import android.support.v7.widget.PopupMenu; 23 | import android.view.LayoutInflater; 24 | import android.view.ViewGroup; 25 | 26 | import com.bumptech.glide.RequestManager; 27 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 28 | 29 | import ooo.oxo.apps.materialize.databinding.MainAppItemBinding; 30 | import ooo.oxo.apps.materialize.util.FilteredSortedListAdapter; 31 | import ooo.oxo.library.databinding.support.widget.BindingRecyclerView; 32 | 33 | public class AppInfoAdapter extends FilteredSortedListAdapter { 34 | 35 | private final Context context; 36 | private final LayoutInflater inflater; 37 | private final RequestManager requestManager; 38 | private final OnItemClickListener listener; 39 | 40 | public AppInfoAdapter(Context context, RequestManager requestManager, 41 | FilteredSortedList.Filter filter, OnItemClickListener listener) { 42 | super(AppInfo.class, filter); 43 | this.context = context; 44 | this.inflater = LayoutInflater.from(context); 45 | this.requestManager = requestManager; 46 | this.listener = listener; 47 | } 48 | 49 | @Override 50 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 51 | return new ViewHolder(parent); 52 | } 53 | 54 | @Override 55 | public void onBindViewHolder(ViewHolder holder, int position) { 56 | AppInfo app = data.get(position); 57 | holder.binding.setApp(app); 58 | requestManager.load(app.cache != null ? app.cache : app) 59 | .diskCacheStrategy(DiskCacheStrategy.NONE) 60 | .into(holder.binding.icon); 61 | } 62 | 63 | @Override 64 | protected int compare(AppInfo lhs, AppInfo rhs) { 65 | return lhs.labelPinyin.pinyinLong.compareTo(rhs.labelPinyin.pinyinLong); 66 | } 67 | 68 | @Override 69 | protected boolean areContentsTheSame(AppInfo oldItem, AppInfo newItem) { 70 | return oldItem.label.equals(newItem.label); 71 | } 72 | 73 | @Override 74 | protected boolean areItemsTheSame(AppInfo item1, AppInfo item2) { 75 | return item1.component.equals(item2.component); 76 | } 77 | 78 | public interface OnItemClickListener { 79 | 80 | void onItemClick(ViewHolder holder); 81 | 82 | void onShowingPopupMenu(ViewHolder holder, PopupMenu menu); 83 | 84 | void onReinstallShortcutClick(ViewHolder holder); 85 | 86 | } 87 | 88 | public class ViewHolder extends BindingRecyclerView.ViewHolder { 89 | 90 | public final PopupMenu popupMenu; 91 | 92 | public ViewHolder(ViewGroup parent) { 93 | super(inflater, R.layout.main_app_item, parent); 94 | 95 | itemView.setOnClickListener(v -> listener.onItemClick(this)); 96 | 97 | popupMenu = new PopupMenu(context, binding.more); 98 | popupMenu.inflate(R.menu.main_item); 99 | popupMenu.getMenu().findItem(R.id.add_to_launcher) 100 | .setOnMenuItemClickListener(i -> { 101 | listener.onReinstallShortcutClick(this); 102 | return true; 103 | }); 104 | 105 | binding.more.setOnClickListener(v -> listener.onShowingPopupMenu(this, popupMenu)); 106 | } 107 | 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/FilteredSortedList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize; 20 | 21 | import android.support.v7.util.SortedList; 22 | 23 | import java.util.ArrayList; 24 | 25 | public class FilteredSortedList extends SortedList { 26 | 27 | private final Filter filter; 28 | 29 | private final ArrayList snapshot = new ArrayList<>(); 30 | 31 | public FilteredSortedList(Class klass, Callback callback, Filter filter) { 32 | super(klass, callback); 33 | this.filter = filter; 34 | } 35 | 36 | public int addWithIndex(T item) { 37 | snapshot.add(item); 38 | return add(item); 39 | } 40 | 41 | public void applyFilter() { 42 | ArrayList removing = new ArrayList<>(); 43 | 44 | for (int i = 0; i < size(); i++) { 45 | T item = get(i); 46 | if (!filter.filter(item)) { 47 | removing.add(item); 48 | } 49 | } 50 | 51 | //noinspection Convert2streamapi 52 | for (T item : removing) { 53 | remove(item); 54 | } 55 | 56 | removing.clear(); 57 | 58 | //noinspection Convert2streamapi 59 | for (T item : snapshot) { 60 | if (filter.filter(item)) { 61 | add(item); 62 | } 63 | } 64 | } 65 | 66 | public interface Filter { 67 | 68 | boolean filter(T item); 69 | 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/Intents.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize; 20 | 21 | import android.content.Intent; 22 | 23 | public class Intents { 24 | 25 | public static final Intent MAIN = new Intent(Intent.ACTION_MAIN) 26 | .addCategory(Intent.CATEGORY_LAUNCHER); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/MainActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize; 20 | 21 | import android.content.Intent; 22 | import android.databinding.DataBindingUtil; 23 | import android.graphics.Bitmap; 24 | import android.graphics.BitmapFactory; 25 | import android.net.Uri; 26 | import android.os.Build; 27 | import android.os.Bundle; 28 | import android.support.annotation.Nullable; 29 | import android.support.v4.app.ActivityCompat; 30 | import android.support.v4.app.ActivityOptionsCompat; 31 | import android.support.v7.widget.PopupMenu; 32 | import android.util.Log; 33 | import android.view.Menu; 34 | import android.view.MenuItem; 35 | import android.widget.Toast; 36 | 37 | import com.bumptech.glide.Glide; 38 | import com.jakewharton.rxbinding.widget.RxTextView; 39 | import com.trello.rxlifecycle.components.support.RxAppCompatActivity; 40 | import com.umeng.analytics.MobclickAgent; 41 | 42 | import java.io.FileNotFoundException; 43 | 44 | import ooo.oxo.apps.materialize.app.ActivityOptionsCompatCompat; 45 | import ooo.oxo.apps.materialize.databinding.MainActivityBinding; 46 | import ooo.oxo.apps.materialize.io.IconCacheManager; 47 | import ooo.oxo.apps.materialize.rx.RxPackageManager; 48 | import ooo.oxo.apps.materialize.util.LauncherUtil; 49 | import ooo.oxo.apps.materialize.util.UpdateUtil; 50 | import rx.Observable; 51 | import rx.android.schedulers.AndroidSchedulers; 52 | import rx.schedulers.Schedulers; 53 | 54 | public class MainActivity extends RxAppCompatActivity 55 | implements AppInfoAdapter.OnItemClickListener { 56 | 57 | private static final String TAG = "MainActivity"; 58 | 59 | private static final int REQUEST_MAKE_ICON = 1; 60 | 61 | private IconCacheManager iconCacheManager; 62 | 63 | private AppInfoAdapter apps; 64 | 65 | private SearchPanelController searchPanelController; 66 | 67 | /** 68 | * @return Observable with apps known in Material Design filtered out 69 | */ 70 | private static Observable.Transformer filterGoodGuys() { 71 | return observable -> observable 72 | .filter(app -> !app.component.getPackageName().startsWith("com.android.")) 73 | .filter(app -> !app.component.getPackageName().startsWith("com.google.")) 74 | .filter(app -> !app.component.getPackageName().startsWith("org.cyanogenmod.")) 75 | .filter(app -> !app.component.getPackageName().startsWith("com.cyanogenmod.")) 76 | .filter(app -> !app.component.getPackageName().startsWith("me.xingrz.")) 77 | .filter(app -> !app.component.getPackageName().startsWith("ooo.oxo.")); 78 | } 79 | 80 | @Override 81 | protected void onCreate(Bundle savedInstanceState) { 82 | super.onCreate(savedInstanceState); 83 | 84 | MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity); 85 | 86 | setSupportActionBar(binding.toolbar); 87 | 88 | searchPanelController = new SearchPanelController(binding.searchBar); 89 | 90 | SearchMatcher searchMatcher = new SearchMatcher(() -> searchPanelController.getKeyword().getText().toString()); 91 | 92 | binding.apps.setAdapter(apps = new AppInfoAdapter(this, Glide.with(this), 93 | searchMatcher, this)); 94 | 95 | RxTextView.afterTextChangeEvents(searchPanelController.getKeyword()) 96 | .compose(bindToLifecycle()) 97 | .subscribe(avoid -> { 98 | apps.data.applyFilter(); 99 | binding.apps.smoothScrollToPosition(0); 100 | }); 101 | 102 | iconCacheManager = new IconCacheManager(this); 103 | 104 | RxPackageManager 105 | .intentActivities(getPackageManager(), Intents.MAIN, 0) 106 | .map(resolve -> AppInfo.from(resolve.activityInfo, getPackageManager(), iconCacheManager)) 107 | .filter(app -> app != null) 108 | .filter(app -> !app.component.getPackageName().equals(BuildConfig.APPLICATION_ID)) 109 | .compose(filterGoodGuys()) 110 | .subscribeOn(Schedulers.io()) 111 | .observeOn(AndroidSchedulers.mainThread()) 112 | .doOnCompleted(() -> binding.apps.smoothScrollToPosition(0)) 113 | .subscribe(apps.data::addWithIndex); 114 | 115 | UpdateUtil.checkForUpdateAndPrompt(this); 116 | } 117 | 118 | @Override 119 | public void onItemClick(AppInfoAdapter.ViewHolder holder) { 120 | int index = holder.getLayoutPosition(); 121 | AppInfo app = apps.data.get(index); 122 | 123 | Intent intent = new Intent(this, AdjustActivity.class); 124 | intent.putExtra("index", index); 125 | intent.putExtra("activity", app.activityInfo); 126 | 127 | int y = Build.VERSION.SDK_INT >= 23 128 | ? (int) (getResources().getDisplayMetrics().heightPixels * 0.16f) 129 | : 0; 130 | 131 | ActivityOptionsCompat options = ActivityOptionsCompatCompat.makeClipRevealAnimation( 132 | holder.itemView, 0, -y, holder.itemView.getWidth(), holder.itemView.getHeight()); 133 | 134 | ActivityCompat.startActivityForResult(this, intent, REQUEST_MAKE_ICON, options.toBundle()); 135 | } 136 | 137 | @Override 138 | public void onShowingPopupMenu(AppInfoAdapter.ViewHolder holder, PopupMenu menu) { 139 | AppInfo app = apps.data.get(holder.getLayoutPosition()); 140 | if (app.cache == null) { 141 | onItemClick(holder); 142 | } else { 143 | menu.show(); 144 | } 145 | } 146 | 147 | @Override 148 | public void onReinstallShortcutClick(AppInfoAdapter.ViewHolder holder) { 149 | AppInfo app = apps.data.get(holder.getLayoutPosition()); 150 | 151 | Observable.just(app) 152 | .compose(bindToLifecycle()) 153 | .filter(a -> a.cache != null) 154 | .observeOn(Schedulers.io()) 155 | .map(a -> decodeIconFromCache(a.cache)) 156 | .filter(icon -> icon != null) 157 | .observeOn(AndroidSchedulers.mainThread()) 158 | .subscribe(icon -> { 159 | LauncherUtil.installShortcut(this, app.getIntent(), app.label, icon); 160 | Toast.makeText(this, R.string.toast_added_to_home, Toast.LENGTH_SHORT).show(); 161 | MobclickAgent.onEvent(this, "install"); 162 | }); 163 | } 164 | 165 | @Nullable 166 | private Bitmap decodeIconFromCache(Uri uri) { 167 | try { 168 | return BitmapFactory.decodeStream(getContentResolver().openInputStream(uri)); 169 | } catch (FileNotFoundException e) { 170 | Log.e(TAG, "Failed reading icon cache from " + uri.toString(), e); 171 | return null; 172 | } 173 | } 174 | 175 | @Override 176 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 177 | switch (requestCode) { 178 | case REQUEST_MAKE_ICON: 179 | if (data != null) { 180 | invalidateIcon(data.getIntExtra("index", 0)); 181 | } 182 | break; 183 | default: 184 | super.onActivityResult(requestCode, resultCode, data); 185 | } 186 | } 187 | 188 | private void invalidateIcon(int index) { 189 | AppInfo app = apps.data.get(index); 190 | if (app.resolveCache(iconCacheManager)) { 191 | app.cache = app.cache 192 | .buildUpon() 193 | .appendQueryParameter("t", String.valueOf(System.currentTimeMillis())) 194 | .build(); 195 | } 196 | 197 | apps.notifyItemChanged(index); 198 | } 199 | 200 | @Override 201 | protected void onResume() { 202 | super.onResume(); 203 | MobclickAgent.onResume(this); 204 | } 205 | 206 | @Override 207 | protected void onPause() { 208 | super.onPause(); 209 | MobclickAgent.onPause(this); 210 | } 211 | 212 | @Override 213 | public boolean onCreateOptionsMenu(Menu menu) { 214 | getMenuInflater().inflate(R.menu.main, menu); 215 | return super.onCreateOptionsMenu(menu); 216 | } 217 | 218 | @Override 219 | public boolean onOptionsItemSelected(MenuItem item) { 220 | switch (item.getItemId()) { 221 | case R.id.about: 222 | startActivity(new Intent(this, AboutActivity.class)); 223 | return true; 224 | case R.id.search: 225 | searchPanelController.open(); 226 | return true; 227 | default: 228 | return super.onOptionsItemSelected(item); 229 | } 230 | } 231 | 232 | @Override 233 | public void onBackPressed() { 234 | if (!searchPanelController.onBackPressed()) { 235 | super.onBackPressed(); 236 | } 237 | } 238 | 239 | } 240 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/MaterializeApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize; 20 | 21 | import android.app.Application; 22 | 23 | import com.umeng.analytics.MobclickAgent; 24 | 25 | import java.util.HashMap; 26 | 27 | import im.fir.sdk.FIR; 28 | 29 | public class MaterializeApplication extends Application { 30 | 31 | @Override 32 | public void onCreate() { 33 | super.onCreate(); 34 | 35 | MobclickAgent.setCatchUncaughtExceptions(false); 36 | 37 | if (BuildConfig.FIR_ENABLED) { 38 | FIR.init(this); 39 | } 40 | 41 | MaterializeSharedState.init(this); 42 | 43 | MobclickAgent.setDebugMode(BuildConfig.DEBUG); 44 | 45 | HashMap event = new HashMap<>(); 46 | event.put("launcher", MaterializeSharedState.getInstance().getLauncher()); 47 | MobclickAgent.onEvent(this, "launcher", event); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/MaterializeSharedState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize; 20 | 21 | import android.content.Context; 22 | 23 | import ooo.oxo.apps.materialize.util.LauncherUtil; 24 | 25 | public class MaterializeSharedState { 26 | 27 | private static MaterializeSharedState instance; 28 | 29 | private final String launcher; 30 | 31 | private MaterializeSharedState(Context context) { 32 | this.launcher = LauncherUtil.resolveLauncherApp(context); 33 | } 34 | 35 | static void init(Context context) { 36 | instance = new MaterializeSharedState(context); 37 | } 38 | 39 | public static MaterializeSharedState getInstance() { 40 | return instance; 41 | } 42 | 43 | public String getLauncher() { 44 | return launcher; 45 | } 46 | 47 | } 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/SearchMatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize; 20 | 21 | import android.text.TextUtils; 22 | 23 | public class SearchMatcher implements FilteredSortedList.Filter { 24 | 25 | private final KeywordProvider provider; 26 | 27 | public SearchMatcher(KeywordProvider provider) { 28 | this.provider = provider; 29 | } 30 | 31 | private static String normalize(String keyword) { 32 | return keyword.toLowerCase().replace(" ", ""); 33 | } 34 | 35 | @Override 36 | @SuppressWarnings("RedundantIfStatement") 37 | public boolean filter(AppInfo app) { 38 | String keyword = normalize(provider.getKeyword()); 39 | 40 | if (TextUtils.isEmpty(keyword)) { 41 | return true; 42 | } 43 | 44 | if (app.label.toLowerCase().contains(keyword)) { 45 | return true; 46 | } 47 | 48 | if (app.component.getPackageName().toLowerCase().contains(keyword)) { 49 | return true; 50 | } 51 | 52 | if (app.labelPinyin.pinyinLong.contains(keyword)) { 53 | return true; 54 | } 55 | 56 | if (app.labelPinyin.pinyinShort.contains(keyword)) { 57 | return true; 58 | } 59 | 60 | return false; 61 | } 62 | 63 | public interface KeywordProvider { 64 | 65 | String getKeyword(); 66 | 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/SearchPanelController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize; 20 | 21 | import android.animation.Animator; 22 | import android.animation.AnimatorListenerAdapter; 23 | import android.annotation.TargetApi; 24 | import android.content.Context; 25 | import android.content.res.Resources; 26 | import android.os.Build; 27 | import android.support.v4.view.animation.FastOutSlowInInterpolator; 28 | import android.view.View; 29 | import android.view.ViewAnimationUtils; 30 | import android.view.ViewGroup; 31 | import android.widget.EditText; 32 | 33 | import ooo.oxo.apps.materialize.util.SoftInputManager; 34 | 35 | public class SearchPanelController { 36 | 37 | private final ViewGroup container; 38 | 39 | private final Resources resources; 40 | 41 | private final EditText keyword; 42 | 43 | private final SoftInputManager softInputManager; 44 | 45 | public SearchPanelController(ViewGroup container) { 46 | this.container = container; 47 | 48 | Context context = container.getContext(); 49 | 50 | this.resources = context.getResources(); 51 | 52 | this.keyword = (EditText) container.findViewById(R.id.keyword); 53 | 54 | container.findViewById(R.id.close).setOnClickListener(v -> clear()); 55 | 56 | this.softInputManager = SoftInputManager.from(keyword); 57 | } 58 | 59 | public EditText getKeyword() { 60 | return keyword; 61 | } 62 | 63 | public void open() { 64 | if (container.getVisibility() == View.VISIBLE) { 65 | return; 66 | } 67 | 68 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 69 | Animator animator = makeSearchPanelAnimator(false); 70 | container.setVisibility(View.VISIBLE); 71 | animator.start(); 72 | } else { 73 | container.setVisibility(View.VISIBLE); 74 | } 75 | 76 | keyword.requestFocus(); 77 | 78 | softInputManager.show(); 79 | } 80 | 81 | public void close() { 82 | if (container.getVisibility() == View.INVISIBLE) { 83 | return; 84 | } 85 | 86 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 87 | Animator animator = makeSearchPanelAnimator(true); 88 | 89 | animator.addListener(new AnimatorListenerAdapter() { 90 | @Override 91 | public void onAnimationEnd(Animator animation) { 92 | container.setVisibility(View.INVISIBLE); 93 | keyword.clearFocus(); 94 | } 95 | }); 96 | 97 | animator.start(); 98 | } else { 99 | container.setVisibility(View.INVISIBLE); 100 | } 101 | 102 | softInputManager.hide(); 103 | } 104 | 105 | public void clear() { 106 | keyword.setText(""); 107 | close(); 108 | } 109 | 110 | public boolean onBackPressed() { 111 | if (container.getVisibility() == View.VISIBLE) { 112 | clear(); 113 | return true; 114 | } else { 115 | return false; 116 | } 117 | } 118 | 119 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 120 | private Animator makeSearchPanelAnimator(boolean reverse) { 121 | int width = container.getWidth(); 122 | 123 | int centerX = container.getRight() 124 | + container.getPaddingRight() 125 | - resources.getDimensionPixelOffset(R.dimen.reveal_right) / 4 * 3; 126 | 127 | int centerY = container.getHeight() / 2; 128 | 129 | Animator animator = ViewAnimationUtils.createCircularReveal(container, 130 | centerX, centerY, 131 | reverse ? width : 0, 132 | reverse ? 0 : width); 133 | 134 | animator.setInterpolator(new FastOutSlowInInterpolator()); 135 | 136 | animator.setDuration(resources.getInteger(android.R.integer.config_mediumAnimTime)); 137 | 138 | return animator; 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/app/ActivityOptionsCompatCompat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.app; 20 | 21 | import android.annotation.TargetApi; 22 | import android.app.ActivityOptions; 23 | import android.os.Build; 24 | import android.os.Bundle; 25 | import android.support.v4.app.ActivityOptionsCompat; 26 | import android.view.View; 27 | 28 | public class ActivityOptionsCompatCompat extends ActivityOptionsCompat { 29 | 30 | public static ActivityOptionsCompat makeClipRevealAnimation( 31 | View source, int startX, int startY, int width, int height) { 32 | if (Build.VERSION.SDK_INT >= 23) { 33 | return new ActivityOptionsImpl23(ActivityOptionsCompat23.makeClipRevealAnimation( 34 | source, startX, startY, width, height)); 35 | } 36 | 37 | return ActivityOptionsCompat.makeScaleUpAnimation(source, startX, startY, width, height); 38 | } 39 | 40 | private static class ActivityOptionsImpl23 extends ActivityOptionsCompatCompat { 41 | 42 | private final ActivityOptionsCompat23 mImpl; 43 | 44 | ActivityOptionsImpl23(ActivityOptionsCompat23 impl) { 45 | mImpl = impl; 46 | } 47 | 48 | @Override 49 | public Bundle toBundle() { 50 | return mImpl.toBundle(); 51 | } 52 | 53 | @Override 54 | public void update(ActivityOptionsCompat otherOptions) { 55 | if (otherOptions instanceof ActivityOptionsImpl23) { 56 | ActivityOptionsImpl23 otherImpl = (ActivityOptionsImpl23) otherOptions; 57 | mImpl.update(otherImpl.mImpl); 58 | } 59 | } 60 | 61 | } 62 | 63 | @TargetApi(23) 64 | private static class ActivityOptionsCompat23 { 65 | 66 | private final ActivityOptions mActivityOptions; 67 | 68 | private ActivityOptionsCompat23(ActivityOptions activityOptions) { 69 | mActivityOptions = activityOptions; 70 | } 71 | 72 | public static ActivityOptionsCompat23 makeClipRevealAnimation( 73 | View source, int startX, int startY, int width, int height) { 74 | return new ActivityOptionsCompat23(ActivityOptions.makeClipRevealAnimation( 75 | source, startX, startY, width, height)); 76 | } 77 | 78 | public Bundle toBundle() { 79 | return mActivityOptions.toBundle(); 80 | } 81 | 82 | public void update(ActivityOptionsCompat23 otherOptions) { 83 | mActivityOptions.update(otherOptions.mActivityOptions); 84 | } 85 | } 86 | 87 | 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/db/Adjustment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.db; 20 | 21 | import android.support.annotation.IntDef; 22 | 23 | import java.lang.annotation.Retention; 24 | import java.lang.annotation.RetentionPolicy; 25 | 26 | import io.realm.RealmObject; 27 | import io.realm.annotations.PrimaryKey; 28 | 29 | public class Adjustment extends RealmObject { 30 | 31 | public static final int SHAPE_SQUARE = 0; 32 | public static final int SHAPE_ROUND = 1; 33 | public static final int SHAPE_SQUARE_SCORE = 2; 34 | public static final int SHAPE_SQUARE_DOGEAR = 3; 35 | public static final int SHAPE_ROUND_SCORE = 4; 36 | 37 | public static final int COLOR_WHITE = 0; 38 | public static final int COLOR_INFINITE = 1; 39 | 40 | @PrimaryKey 41 | private String component; 42 | 43 | @Shape 44 | private int shape = SHAPE_SQUARE; 45 | 46 | private float padding = 0; 47 | 48 | @Color 49 | private int color = COLOR_WHITE; 50 | 51 | public Adjustment() { 52 | } 53 | 54 | public Adjustment(String component) { 55 | this.component = component; 56 | } 57 | 58 | public String getComponent() { 59 | return component; 60 | } 61 | 62 | public void setComponent(String component) { 63 | this.component = component; 64 | } 65 | 66 | @Shape 67 | public int getShape() { 68 | return shape; 69 | } 70 | 71 | public void setShape(@Shape int shape) { 72 | this.shape = shape; 73 | } 74 | 75 | public float getPadding() { 76 | return padding; 77 | } 78 | 79 | public void setPadding(float padding) { 80 | this.padding = padding; 81 | } 82 | 83 | @Color 84 | public int getColor() { 85 | return color; 86 | } 87 | 88 | public void setColor(@Color int color) { 89 | this.color = color; 90 | } 91 | 92 | @Retention(RetentionPolicy.SOURCE) 93 | @IntDef({SHAPE_SQUARE, SHAPE_SQUARE_SCORE, SHAPE_SQUARE_DOGEAR, SHAPE_ROUND, SHAPE_ROUND_SCORE}) 94 | public @interface Shape { 95 | } 96 | 97 | @Retention(RetentionPolicy.SOURCE) 98 | @IntDef({COLOR_WHITE, COLOR_INFINITE}) 99 | public @interface Color { 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/graphics/CompositeDrawable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.graphics; 20 | 21 | import android.content.res.Resources; 22 | import android.graphics.Bitmap; 23 | import android.graphics.BitmapFactory; 24 | import android.graphics.Canvas; 25 | import android.graphics.Color; 26 | import android.graphics.ColorFilter; 27 | import android.graphics.Paint; 28 | import android.graphics.PixelFormat; 29 | import android.graphics.PorterDuff; 30 | import android.graphics.PorterDuffXfermode; 31 | import android.graphics.Rect; 32 | import android.graphics.RectF; 33 | import android.graphics.drawable.Drawable; 34 | import android.support.annotation.DimenRes; 35 | import android.support.annotation.DrawableRes; 36 | import android.support.annotation.Nullable; 37 | 38 | import ooo.oxo.apps.materialize.R; 39 | 40 | public class CompositeDrawable extends Drawable { 41 | 42 | private static final int FLAG_SCALES = Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG; 43 | 44 | private static final int SCORE_COLOR = Color.argb(0x10, 0, 0, 0); 45 | 46 | private final Resources resources; 47 | 48 | private final RectF foregroundBounds = new RectF(); 49 | 50 | private final Rect backgroundBounds = new Rect(); 51 | 52 | private final Rect scoreBounds = new Rect(); 53 | 54 | private final Paint paint = new Paint(); 55 | 56 | @Nullable 57 | private Bitmap source; 58 | 59 | private Shape shape; 60 | 61 | private float padding = 0; 62 | 63 | private Drawable background; 64 | 65 | private Bitmap back; 66 | 67 | private Bitmap mask; 68 | 69 | private Bitmap fore; 70 | 71 | public CompositeDrawable(Resources resources) { 72 | this.resources = resources; 73 | setShape(Shape.SQUARE); 74 | } 75 | 76 | public void setSource(@Nullable Bitmap source) { 77 | this.source = source; 78 | invalidateSelf(); 79 | } 80 | 81 | public void setShape(Shape shape) { 82 | this.shape = shape; 83 | invalidateForegroundBounds(); 84 | invalidateBackgroundBounds(); 85 | invalidateBitmaps(); 86 | invalidateSelf(); 87 | } 88 | 89 | public void setPadding(float padding) { 90 | this.padding = padding; 91 | invalidateForegroundBounds(); 92 | invalidateSelf(); 93 | } 94 | 95 | public void setBackground(Drawable background) { 96 | this.background = background; 97 | invalidateSelf(); 98 | } 99 | 100 | @Override 101 | protected void onBoundsChange(Rect bounds) { 102 | super.onBoundsChange(bounds); 103 | invalidateForegroundBounds(); 104 | invalidateBackgroundBounds(); 105 | invalidateScoreBounds(); 106 | } 107 | 108 | private void invalidateForegroundBounds() { 109 | foregroundBounds.set(getBounds()); 110 | applyForegroundBounds(foregroundBounds); 111 | } 112 | 113 | private void applyForegroundBounds(RectF foregroundBounds) { 114 | float finalPadding = padding + shape.getPadding(resources); 115 | foregroundBounds.inset(finalPadding, finalPadding); 116 | } 117 | 118 | private void invalidateBackgroundBounds() { 119 | backgroundBounds.set(getBounds()); 120 | applyBackgroundBounds(backgroundBounds); 121 | } 122 | 123 | private void applyBackgroundBounds(Rect backgroundBounds) { 124 | int offset = resources.getDimensionPixelOffset(shape.padding); 125 | backgroundBounds.inset(offset, offset); 126 | } 127 | 128 | private void invalidateScoreBounds() { 129 | scoreBounds.set(getBounds()); 130 | applyScoreBounds(scoreBounds); 131 | } 132 | 133 | private void applyScoreBounds(Rect scoreBounds) { 134 | scoreBounds.bottom = scoreBounds.centerY(); 135 | } 136 | 137 | private void invalidateBitmaps() { 138 | if (back != null) { 139 | back.recycle(); 140 | } 141 | 142 | back = shape.getBackBitmap(resources); 143 | 144 | if (mask != null) { 145 | mask.recycle(); 146 | } 147 | 148 | mask = shape.getMaskBitmap(resources); 149 | 150 | if (fore != null) { 151 | fore.recycle(); 152 | } 153 | 154 | fore = shape.getForeBitmap(resources); 155 | } 156 | 157 | @Override 158 | public void draw(Canvas canvas) { 159 | drawInternal(canvas, true, getBounds(), foregroundBounds, backgroundBounds, scoreBounds); 160 | } 161 | 162 | public void drawTo(Canvas canvas, boolean antiAliasing) { 163 | Rect bounds = new Rect(0, 0, canvas.getWidth(), canvas.getHeight()); 164 | 165 | RectF foregroundBounds = new RectF(bounds); 166 | applyForegroundBounds(foregroundBounds); 167 | 168 | Rect backgroundBounds = new Rect(bounds); 169 | applyBackgroundBounds(backgroundBounds); 170 | 171 | Rect scoreBounds = new Rect(bounds); 172 | applyScoreBounds(scoreBounds); 173 | 174 | drawInternal(canvas, antiAliasing, bounds, foregroundBounds, backgroundBounds, scoreBounds); 175 | } 176 | 177 | private void drawInternal(Canvas canvas, boolean antiAliasing, 178 | Rect bounds, RectF foregroundBounds, Rect backgroundBounds, Rect scoreBounds) { 179 | paint.setFlags(antiAliasing ? FLAG_SCALES : 0); 180 | 181 | canvas.drawBitmap(back, null, bounds, paint); 182 | 183 | canvas.saveLayer( 184 | bounds.left, bounds.top, bounds.right, bounds.bottom, 185 | null, Canvas.ALL_SAVE_FLAG); 186 | 187 | if (background != null) { 188 | background.setBounds(backgroundBounds); 189 | background.draw(canvas); 190 | } 191 | 192 | // always anti-aliasing on source bitmap because we scaled it 193 | if (source != null) { 194 | paint.setFlags(FLAG_SCALES); 195 | canvas.drawBitmap(source, null, foregroundBounds, paint); 196 | } 197 | 198 | paint.setFlags(antiAliasing ? FLAG_SCALES : 0); 199 | 200 | if (shape.score) { 201 | paint.setColor(SCORE_COLOR); 202 | canvas.drawRect(scoreBounds, paint); 203 | paint.setColor(Color.WHITE); 204 | } 205 | 206 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); 207 | canvas.drawBitmap(mask, null, bounds, paint); 208 | paint.setXfermode(null); 209 | 210 | canvas.drawBitmap(fore, null, bounds, paint); 211 | 212 | canvas.restore(); 213 | } 214 | 215 | @Override 216 | public void setAlpha(int alpha) { 217 | // not support 218 | } 219 | 220 | @Override 221 | public void setColorFilter(ColorFilter colorFilter) { 222 | // not support 223 | } 224 | 225 | @Override 226 | public int getOpacity() { 227 | return PixelFormat.TRANSLUCENT; 228 | } 229 | 230 | public enum Shape { 231 | SQUARE( 232 | R.dimen.default_padding_square, 233 | R.drawable.stencil_square_back, 234 | R.drawable.stencil_square_mask, 235 | R.drawable.stencil_square_fore, 236 | false 237 | ), 238 | 239 | SQUARE_SCORE( 240 | R.dimen.default_padding_square, 241 | R.drawable.stencil_square_back, 242 | R.drawable.stencil_square_mask, 243 | R.drawable.stencil_square_fore, 244 | true 245 | ), 246 | 247 | SQUARE_DOGEAR( 248 | R.dimen.default_padding_square, 249 | R.drawable.stencil_square_dogear_back, 250 | R.drawable.stencil_square_dogear_mask, 251 | R.drawable.stencil_square_dogear_fore, 252 | false 253 | ), 254 | 255 | ROUND( 256 | R.dimen.default_padding_round, 257 | R.drawable.stencil_round_back, 258 | R.drawable.stencil_round_mask, 259 | R.drawable.stencil_round_fore, 260 | false 261 | ), 262 | 263 | ROUND_SCORE( 264 | R.dimen.default_padding_round, 265 | R.drawable.stencil_round_back, 266 | R.drawable.stencil_round_mask, 267 | R.drawable.stencil_round_fore, 268 | true 269 | ); 270 | 271 | @DimenRes 272 | public final int padding; 273 | 274 | @DrawableRes 275 | public final int back; 276 | 277 | @DrawableRes 278 | public final int mask; 279 | 280 | @DrawableRes 281 | public final int fore; 282 | 283 | public final boolean score; 284 | 285 | Shape(int padding, @DrawableRes int back, @DrawableRes int mask, @DrawableRes int fore, boolean score) { 286 | this.padding = padding; 287 | this.back = back; 288 | this.mask = mask; 289 | this.fore = fore; 290 | this.score = score; 291 | } 292 | 293 | public float getPadding(Resources resources) { 294 | return resources.getDimension(padding); 295 | } 296 | 297 | public Bitmap getBitmap(Resources resources, @DrawableRes int drawable) { 298 | BitmapFactory.Options options = new BitmapFactory.Options(); 299 | options.inScaled = false; 300 | 301 | return BitmapFactory.decodeResource(resources, drawable, options); 302 | } 303 | 304 | public Bitmap getBackBitmap(Resources resources) { 305 | return getBitmap(resources, back); 306 | } 307 | 308 | public Bitmap getMaskBitmap(Resources resources) { 309 | return getBitmap(resources, mask); 310 | } 311 | 312 | public Bitmap getForeBitmap(Resources resources) { 313 | return getBitmap(resources, fore); 314 | } 315 | 316 | } 317 | 318 | } 319 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/graphics/InfiniteDrawable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.graphics; 20 | 21 | import android.graphics.Bitmap; 22 | import android.graphics.Canvas; 23 | import android.graphics.Color; 24 | import android.graphics.ColorFilter; 25 | import android.graphics.Paint; 26 | import android.graphics.PixelFormat; 27 | import android.graphics.Rect; 28 | import android.graphics.RectF; 29 | import android.graphics.drawable.Drawable; 30 | import android.support.annotation.ColorInt; 31 | import android.support.annotation.Nullable; 32 | 33 | public class InfiniteDrawable extends Drawable { 34 | 35 | private final Bitmap left; 36 | private final Bitmap top; 37 | private final Bitmap right; 38 | private final Bitmap bottom; 39 | 40 | private final RectF regionLeft = new RectF(); 41 | private final RectF regionTop = new RectF(); 42 | private final RectF regionRight = new RectF(); 43 | private final RectF regionBottom = new RectF(); 44 | 45 | @ColorInt 46 | private final int colorTL; 47 | 48 | @ColorInt 49 | private final int colorTR; 50 | 51 | @ColorInt 52 | private final int colorBL; 53 | 54 | @ColorInt 55 | private final int colorBR; 56 | 57 | private final RectF regionTL = new RectF(); 58 | private final RectF regionTR = new RectF(); 59 | private final RectF regionBL = new RectF(); 60 | private final RectF regionBR = new RectF(); 61 | 62 | private final Paint paint = new Paint(); 63 | 64 | private float padding = 0; 65 | 66 | public InfiniteDrawable(Bitmap left, Bitmap top, Bitmap right, Bitmap bottom, 67 | @ColorInt int colorTL, @ColorInt int colorTR, 68 | @ColorInt int colorBL, @ColorInt int colorBR) { 69 | this.left = left; 70 | this.top = top; 71 | this.right = right; 72 | this.bottom = bottom; 73 | 74 | this.colorTL = colorTL; 75 | this.colorTR = colorTR; 76 | this.colorBL = colorBL; 77 | this.colorBR = colorBR; 78 | } 79 | 80 | private static boolean isOpaque(@ColorInt int color) { 81 | return Color.alpha(color) == 0xFF; 82 | } 83 | 84 | @Nullable 85 | public static InfiniteDrawable from(Bitmap source) { 86 | Bitmap left = Bitmap.createBitmap(1, source.getHeight(), Bitmap.Config.ARGB_8888); 87 | Bitmap right = Bitmap.createBitmap(1, source.getHeight(), Bitmap.Config.ARGB_8888); 88 | Bitmap top = Bitmap.createBitmap(source.getWidth(), 1, Bitmap.Config.ARGB_8888); 89 | Bitmap bottom = Bitmap.createBitmap(source.getWidth(), 1, Bitmap.Config.ARGB_8888); 90 | 91 | @ColorInt 92 | int tl = Color.TRANSPARENT; 93 | 94 | @ColorInt 95 | int tr = Color.TRANSPARENT; 96 | 97 | @ColorInt 98 | int bl = Color.TRANSPARENT; 99 | 100 | @ColorInt 101 | int br = Color.TRANSPARENT; 102 | 103 | // middle 104 | for (int y = 0; y < source.getHeight(); y++) { 105 | int color; 106 | 107 | color = Color.TRANSPARENT; 108 | 109 | for (int x = 0; x < source.getWidth() / 2; x++) { 110 | int i = source.getPixel(x, y); 111 | if (isOpaque(i)) { 112 | color = i; 113 | break; 114 | } 115 | } 116 | 117 | left.setPixel(0, y, color); 118 | 119 | color = Color.TRANSPARENT; 120 | 121 | for (int x = source.getWidth() - 1; x > source.getWidth() / 2; x--) { 122 | int i = source.getPixel(x, y); 123 | if (isOpaque(i)) { 124 | color = i; 125 | break; 126 | } 127 | } 128 | 129 | right.setPixel(0, y, color); 130 | } 131 | 132 | // top left 133 | for (int y = 0; y < source.getHeight() / 2; y++) { 134 | boolean opaque = false; 135 | 136 | for (int x = source.getWidth() / 2; x >= 0; x--) { 137 | int i = source.getPixel(x, y); 138 | 139 | if (isOpaque(i)) { 140 | top.setPixel(x, 0, tl = i); 141 | opaque = true; 142 | } 143 | } 144 | 145 | if (opaque) { 146 | break; 147 | } 148 | } 149 | 150 | // top right 151 | for (int y = 0; y < source.getHeight() / 2; y++) { 152 | boolean opaque = false; 153 | 154 | for (int x = source.getWidth() / 2; x < source.getWidth(); x++) { 155 | int i = source.getPixel(x, y); 156 | 157 | if (isOpaque(i)) { 158 | top.setPixel(x, 0, tr = i); 159 | opaque = true; 160 | } 161 | } 162 | 163 | if (opaque) { 164 | break; 165 | } 166 | } 167 | 168 | // bottom left 169 | for (int y = source.getHeight() - 1; y > source.getHeight() / 2; y--) { 170 | boolean opaque = false; 171 | 172 | for (int x = source.getWidth() / 2; x >= 0; x--) { 173 | int i = source.getPixel(x, y); 174 | 175 | if (isOpaque(i)) { 176 | bottom.setPixel(x, 0, bl = i); 177 | opaque = true; 178 | } 179 | } 180 | 181 | if (opaque) { 182 | break; 183 | } 184 | } 185 | 186 | // bottom right 187 | for (int y = source.getHeight() - 1; y > source.getHeight() / 2; y--) { 188 | boolean opaque = false; 189 | 190 | for (int x = source.getWidth() / 2; x < source.getWidth(); x++) { 191 | int i = source.getPixel(x, y); 192 | 193 | if (isOpaque(i)) { 194 | bottom.setPixel(x, 0, br = i); 195 | opaque = true; 196 | } 197 | } 198 | 199 | if (opaque) { 200 | break; 201 | } 202 | } 203 | 204 | return new InfiniteDrawable(left, top, right, bottom, tl, tr, bl, br); 205 | } 206 | 207 | public float getPadding() { 208 | return padding; 209 | } 210 | 211 | public void setPadding(float padding) { 212 | this.padding = padding; 213 | invalidatePadding(); 214 | invalidateSelf(); 215 | } 216 | 217 | @Override 218 | protected void onBoundsChange(Rect bounds) { 219 | super.onBoundsChange(bounds); 220 | invalidatePadding(); 221 | } 222 | 223 | private void invalidatePadding() { 224 | Rect bounds = getBounds(); 225 | 226 | regionTop.set(bounds.left + padding, bounds.top, bounds.right - padding, bounds.centerY()); 227 | regionBottom.set(bounds.left + padding, bounds.centerY(), bounds.right - padding, bounds.bottom); 228 | 229 | regionLeft.set(bounds.left, bounds.top + padding, bounds.centerX(), bounds.bottom - padding); 230 | regionRight.set(bounds.centerX(), bounds.top + padding, bounds.right, bounds.bottom - padding); 231 | 232 | regionTL.set(bounds.left, bounds.top, bounds.centerX(), bounds.centerY()); 233 | regionTR.set(bounds.centerX(), bounds.top, bounds.right, bounds.centerY()); 234 | regionBL.set(bounds.left, bounds.centerY(), bounds.centerX(), bounds.bottom); 235 | regionBR.set(bounds.centerX(), bounds.centerY(), bounds.right, bounds.bottom); 236 | } 237 | 238 | @Override 239 | public void draw(Canvas canvas) { 240 | paint.setColor(colorTL); 241 | canvas.drawRect(regionTL, paint); 242 | 243 | paint.setColor(colorTR); 244 | canvas.drawRect(regionTR, paint); 245 | 246 | paint.setColor(colorBL); 247 | canvas.drawRect(regionBL, paint); 248 | 249 | paint.setColor(colorBR); 250 | canvas.drawRect(regionBR, paint); 251 | 252 | canvas.drawBitmap(top, null, regionTop, null); 253 | canvas.drawBitmap(bottom, null, regionBottom, null); 254 | 255 | canvas.drawBitmap(left, null, regionLeft, null); 256 | canvas.drawBitmap(right, null, regionRight, null); 257 | } 258 | 259 | @Override 260 | public void setAlpha(int alpha) { 261 | // not support 262 | } 263 | 264 | @Override 265 | public void setColorFilter(ColorFilter colorFilter) { 266 | // not support 267 | } 268 | 269 | @Override 270 | public int getOpacity() { 271 | return PixelFormat.OPAQUE; 272 | } 273 | 274 | } 275 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/graphics/ShapeDrawable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.graphics; 20 | 21 | import android.content.res.Resources; 22 | import android.graphics.Canvas; 23 | import android.graphics.Rect; 24 | import android.graphics.drawable.ColorDrawable; 25 | import android.graphics.drawable.Drawable; 26 | import android.support.annotation.ColorRes; 27 | 28 | import ooo.oxo.apps.materialize.R; 29 | 30 | public class ShapeDrawable extends CompositeDrawable { 31 | 32 | private boolean checked = false; 33 | 34 | private Drawable indicator; 35 | 36 | private Rect indicatorRegion = new Rect(); 37 | 38 | private int size; 39 | 40 | @SuppressWarnings("deprecation") 41 | public ShapeDrawable(Resources resources, Shape shape, @ColorRes int color) { 42 | super(resources); 43 | indicator = resources.getDrawable(R.drawable.ic_check_white_24dp); 44 | size = resources.getDimensionPixelSize(R.dimen.launcher_size); 45 | setShape(shape); 46 | setBackground(new ColorDrawable(resources.getColor(color))); 47 | } 48 | 49 | @Override 50 | public boolean isStateful() { 51 | return true; 52 | } 53 | 54 | @Override 55 | protected boolean onStateChange(int[] state) { 56 | if (state == null) { 57 | return false; 58 | } 59 | 60 | boolean checked = false; 61 | for (int i : state) { 62 | if (i == android.R.attr.state_checked) { 63 | checked = true; 64 | } 65 | } 66 | 67 | if (this.checked != checked) { 68 | this.checked = checked; 69 | invalidateSelf(); 70 | return true; 71 | } else { 72 | return false; 73 | } 74 | } 75 | 76 | @Override 77 | protected void onBoundsChange(Rect bounds) { 78 | super.onBoundsChange(bounds); 79 | indicatorRegion.set(bounds); 80 | indicatorRegion.inset(indicator.getIntrinsicWidth() / 2, indicator.getIntrinsicHeight() / 2); 81 | indicator.setBounds(indicatorRegion); 82 | } 83 | 84 | @Override 85 | public int getIntrinsicWidth() { 86 | return size; 87 | } 88 | 89 | @Override 90 | public int getIntrinsicHeight() { 91 | return size; 92 | } 93 | 94 | @Override 95 | public void draw(Canvas canvas) { 96 | super.draw(canvas); 97 | if (checked) { 98 | indicator.draw(canvas); 99 | } 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/graphics/TransparencyDrawable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.graphics; 20 | 21 | import android.content.res.Resources; 22 | import android.graphics.Canvas; 23 | import android.graphics.Color; 24 | import android.graphics.ColorFilter; 25 | import android.graphics.Paint; 26 | import android.graphics.PixelFormat; 27 | import android.graphics.Rect; 28 | import android.graphics.drawable.Drawable; 29 | import android.support.annotation.DimenRes; 30 | 31 | /** 32 | * A drawable that generates transparency grid 33 | */ 34 | public class TransparencyDrawable extends Drawable { 35 | 36 | public static final int COLOR_BACKGROUND = Color.argb(0xFF, 0xF0, 0xF0, 0xF0); 37 | public static final int COLOR_CELL = Color.argb(0x10, 0x00, 0x00, 0x00); 38 | 39 | private final float size; 40 | 41 | private final Paint paint; 42 | 43 | /** 44 | * @param size Size of a cell 45 | */ 46 | public TransparencyDrawable(float size) { 47 | this.size = size; 48 | this.paint = new Paint(); 49 | this.paint.setColor(TransparencyDrawable.COLOR_CELL); 50 | } 51 | 52 | public TransparencyDrawable(Resources resources, @DimenRes int size) { 53 | this(resources.getDimensionPixelSize(size)); 54 | } 55 | 56 | @Override 57 | public void draw(Canvas canvas) { 58 | Rect bounds = getBounds(); 59 | 60 | canvas.drawColor(COLOR_BACKGROUND); 61 | 62 | for (float x = bounds.left; x < bounds.right; x += size) { 63 | for (float y = bounds.top; y < bounds.bottom; y += size * 2) { 64 | float t = y + (x % (size * 2)); 65 | float r = Math.min(x + size, bounds.right); 66 | float b = Math.min(t + size, bounds.bottom); 67 | canvas.drawRect(x, t, r, b, paint); 68 | } 69 | } 70 | } 71 | 72 | @Override 73 | public void setAlpha(int alpha) { 74 | // not support 75 | } 76 | 77 | @Override 78 | public void setColorFilter(ColorFilter colorFilter) { 79 | // not support 80 | } 81 | 82 | @Override 83 | public int getOpacity() { 84 | return PixelFormat.TRANSLUCENT; 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/io/DrawableGlideMode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.io; 20 | 21 | import android.content.Context; 22 | 23 | import com.bumptech.glide.Glide; 24 | import com.bumptech.glide.GlideBuilder; 25 | import com.bumptech.glide.module.GlideModule; 26 | 27 | import java.io.InputStream; 28 | 29 | import ooo.oxo.apps.materialize.AppInfo; 30 | 31 | public class DrawableGlideMode implements GlideModule { 32 | 33 | @Override 34 | public void applyOptions(Context context, GlideBuilder builder) { 35 | } 36 | 37 | @Override 38 | public void registerComponents(Context context, Glide glide) { 39 | glide.register(AppInfo.class, InputStream.class, new DrawableStreamLoader.Factory()); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/io/DrawableStreamFetcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.io; 20 | 21 | import android.content.res.Resources; 22 | import android.util.TypedValue; 23 | 24 | import com.bumptech.glide.Priority; 25 | import com.bumptech.glide.load.data.DataFetcher; 26 | 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | 30 | public class DrawableStreamFetcher implements DataFetcher { 31 | 32 | private final Resources res; 33 | 34 | private final int id; 35 | 36 | private final TypedValue value; 37 | 38 | private InputStream stream; 39 | 40 | public DrawableStreamFetcher(Resources res, int id, TypedValue value) { 41 | this.res = res; 42 | this.id = id; 43 | this.value = value; 44 | } 45 | 46 | @Override 47 | public InputStream loadData(Priority priority) throws Exception { 48 | stream = res.openRawResource(id, value); 49 | return stream; 50 | } 51 | 52 | @Override 53 | public void cleanup() { 54 | if (stream != null) { 55 | try { 56 | stream.close(); 57 | } catch (IOException ignored) { 58 | } 59 | } 60 | } 61 | 62 | @Override 63 | public String getId() { 64 | return String.format("%s@%d", res.getResourceName(id), value.density); 65 | } 66 | 67 | @Override 68 | public void cancel() { 69 | // not support 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/io/DrawableStreamLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.io; 20 | 21 | import android.content.Context; 22 | 23 | import com.bumptech.glide.load.data.DataFetcher; 24 | import com.bumptech.glide.load.model.GenericLoaderFactory; 25 | import com.bumptech.glide.load.model.ModelLoader; 26 | import com.bumptech.glide.load.model.ModelLoaderFactory; 27 | import com.bumptech.glide.load.model.stream.StreamModelLoader; 28 | 29 | import java.io.InputStream; 30 | 31 | import ooo.oxo.apps.materialize.AppInfo; 32 | 33 | public class DrawableStreamLoader implements StreamModelLoader { 34 | 35 | @Override 36 | public DataFetcher getResourceFetcher(AppInfo model, int width, int height) { 37 | return new DrawableStreamFetcher(model.res, model.iconResId, model.iconValue); 38 | } 39 | 40 | public static class Factory implements ModelLoaderFactory { 41 | 42 | @Override 43 | public ModelLoader build(Context context, GenericLoaderFactory factories) { 44 | return new DrawableStreamLoader(); 45 | } 46 | 47 | @Override 48 | public void teardown() { 49 | } 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/io/IconCacheManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.io; 20 | 21 | import android.content.Context; 22 | import android.net.Uri; 23 | import android.support.annotation.Nullable; 24 | import android.util.Log; 25 | 26 | import java.io.File; 27 | import java.io.IOException; 28 | 29 | import ooo.oxo.apps.materialize.AppInfo; 30 | 31 | public class IconCacheManager extends IconManager { 32 | 33 | private static final String TAG = "IconCacheManager"; 34 | 35 | @SuppressWarnings("SpellCheckingInspection") 36 | private static final String NO_MEDIA = ".nomedia"; 37 | 38 | public IconCacheManager(Context context) { 39 | super(new File(context.getExternalCacheDir(), "icons")); 40 | } 41 | 42 | @Nullable 43 | public Uri get(AppInfo app) { 44 | File file = makeIconFile(app); 45 | 46 | if (file == null || !file.isFile()) { 47 | return null; 48 | } else { 49 | return Uri.fromFile(file); 50 | } 51 | } 52 | 53 | @Nullable 54 | @Override 55 | protected File makeIconFile(AppInfo app) { 56 | File dir = makeIconDirectory(app); 57 | return dir == null ? null : new File(dir, app.component.getClassName()); 58 | } 59 | 60 | @Nullable 61 | private File makeIconDirectory(AppInfo app) { 62 | File dir = new File(root, app.component.getPackageName()); 63 | 64 | if (!dir.mkdirs() && !dir.isDirectory()) { 65 | Log.e(TAG, "Failed to create icon directory for package at " + dir.getAbsolutePath()); 66 | return null; 67 | } 68 | 69 | createNoMediaFile(dir); 70 | 71 | return dir; 72 | } 73 | 74 | private boolean createNoMediaFile(File dir) { 75 | try { 76 | File noMedia = new File(dir, NO_MEDIA); 77 | return noMedia.isFile() || noMedia.createNewFile(); 78 | } catch (IOException e) { 79 | return false; 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/io/IconManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.io; 20 | 21 | import android.graphics.Bitmap; 22 | import android.net.Uri; 23 | import android.support.annotation.Nullable; 24 | import android.util.Log; 25 | 26 | import java.io.File; 27 | import java.io.FileNotFoundException; 28 | import java.io.FileOutputStream; 29 | import java.io.IOException; 30 | import java.io.OutputStream; 31 | 32 | import ooo.oxo.apps.materialize.AppInfo; 33 | 34 | public abstract class IconManager { 35 | 36 | private static final String TAG = "IconManager"; 37 | 38 | protected final File root; 39 | 40 | public IconManager(File root) { 41 | this.root = root; 42 | } 43 | 44 | public void save(AppInfo app, Bitmap icon) { 45 | File file = makeIconFile(app); 46 | 47 | if (file == null) { 48 | Log.e(TAG, "Failed to prepare icon path for " + app.component.flattenToString()); 49 | return; 50 | } 51 | 52 | OutputStream output; 53 | 54 | try { 55 | output = new FileOutputStream(file); 56 | } catch (FileNotFoundException e) { 57 | Log.e(TAG, "Failed to write icon to " + file.getAbsolutePath(), e); 58 | return; 59 | } 60 | 61 | if (!icon.compress(Bitmap.CompressFormat.PNG, 100, output)) { 62 | Log.e(TAG, "Failed to compress icon to " + file.getAbsolutePath()); 63 | } 64 | 65 | try { 66 | output.close(); 67 | } catch (IOException ignored) { 68 | } 69 | 70 | Log.d(TAG, "Saved icon " + file.getAbsolutePath()); 71 | } 72 | 73 | public void delete(AppInfo app) { 74 | File file = makeIconFile(app); 75 | if (file != null && file.isFile() && !file.delete()) { 76 | Log.e(TAG, "Failed to delete icon at " + file.getAbsolutePath()); 77 | } 78 | } 79 | 80 | @Nullable 81 | public Uri get(AppInfo app) { 82 | File file = makeIconFile(app); 83 | 84 | if (file == null || !file.isFile()) { 85 | return null; 86 | } else { 87 | return Uri.fromFile(file); 88 | } 89 | } 90 | 91 | @Nullable 92 | protected abstract File makeIconFile(AppInfo app); 93 | 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/io/PublicIconManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.io; 20 | 21 | import android.content.Context; 22 | import android.graphics.Bitmap; 23 | import android.media.MediaScannerConnection; 24 | import android.os.Environment; 25 | import android.support.annotation.Nullable; 26 | import android.util.Log; 27 | 28 | import java.io.File; 29 | 30 | import ooo.oxo.apps.materialize.AppInfo; 31 | 32 | public class PublicIconManager extends IconManager { 33 | 34 | private static final String TAG = "PublicIconManager"; 35 | 36 | private final Context context; 37 | 38 | public PublicIconManager(Context context) { 39 | super(new File(Environment.getExternalStorageDirectory(), "Materialize")); 40 | this.context = context.getApplicationContext(); 41 | } 42 | 43 | @Override 44 | public void save(AppInfo app, Bitmap icon) { 45 | super.save(app, icon); 46 | 47 | File file = makeIconFile(app); 48 | if (file != null) { 49 | notifyMediaScanning(file); 50 | } 51 | } 52 | 53 | @Nullable 54 | @Override 55 | protected File makeIconFile(AppInfo app) { 56 | if (ensureDirectory()) { 57 | return new File(root, app.component.getPackageName() + "-" + app.component.getClassName() + ".PNG"); 58 | } else { 59 | Log.e(TAG, "Failed to create icon directory for package at " + root.getAbsolutePath()); 60 | return null; 61 | } 62 | } 63 | 64 | private boolean ensureDirectory() { 65 | return root.mkdirs() || root.isDirectory(); 66 | } 67 | 68 | private void notifyMediaScanning(File file) { 69 | MediaScannerConnection.scanFile(context, new String[]{file.getPath()}, null, null); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/rx/RxPackageManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.rx; 20 | 21 | import android.content.Intent; 22 | import android.content.pm.PackageManager; 23 | import android.content.pm.ResolveInfo; 24 | 25 | import rx.Observable; 26 | 27 | public class RxPackageManager { 28 | 29 | public static Observable intentActivities(PackageManager packageManager, Intent intent, int flags) { 30 | return Observable.defer(() -> Observable.from(packageManager.queryIntentActivities(intent, flags))); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/util/DisplayMetricsCompat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.util; 20 | 21 | import android.util.DisplayMetrics; 22 | 23 | public class DisplayMetricsCompat extends DisplayMetrics { 24 | 25 | public static final int DENSITY_XXXHIGH = 640; 26 | 27 | public static final int DENSITY_XXHIGH = 480; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/util/FilteredSortedListAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.util; 20 | 21 | import android.support.v7.widget.RecyclerView; 22 | import android.support.v7.widget.util.SortedListAdapterCallback; 23 | 24 | import ooo.oxo.apps.materialize.FilteredSortedList; 25 | 26 | public abstract class FilteredSortedListAdapter extends RecyclerView.Adapter { 27 | 28 | public final FilteredSortedList data; 29 | 30 | public FilteredSortedListAdapter(Class type, FilteredSortedList.Filter filter) { 31 | this.data = new FilteredSortedList<>(type, new SortedListAdapterCallback(this) { 32 | @Override 33 | public int compare(T lhs, T rhs) { 34 | return FilteredSortedListAdapter.this.compare(lhs, rhs); 35 | } 36 | 37 | @Override 38 | public boolean areContentsTheSame(T oldItem, T newItem) { 39 | return FilteredSortedListAdapter.this.areContentsTheSame(oldItem, newItem); 40 | } 41 | 42 | @Override 43 | public boolean areItemsTheSame(T item1, T item2) { 44 | return FilteredSortedListAdapter.this.areItemsTheSame(item1, item2); 45 | } 46 | }, filter); 47 | } 48 | 49 | @Override 50 | public final int getItemCount() { 51 | return data.size(); 52 | } 53 | 54 | protected abstract int compare(T lhs, T rhs); 55 | 56 | protected abstract boolean areContentsTheSame(T oldItem, T newItem); 57 | 58 | protected abstract boolean areItemsTheSame(T item1, T item2); 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/util/LauncherUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.util; 20 | 21 | import android.content.Context; 22 | import android.content.Intent; 23 | import android.content.pm.PackageManager; 24 | import android.graphics.Bitmap; 25 | import android.support.annotation.Nullable; 26 | 27 | public class LauncherUtil { 28 | 29 | public static void installShortcut(Context context, Intent shortcut, String label, Bitmap icon) { 30 | Intent intent = new Intent("com.android.launcher.action.INSTALL_SHORTCUT"); 31 | intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcut); 32 | intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, label); 33 | intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon); 34 | context.sendBroadcast(intent); 35 | } 36 | 37 | @Nullable 38 | public static String resolveLauncherApp(Context context) { 39 | try { 40 | return context.getPackageManager().resolveActivity( 41 | new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME), 42 | PackageManager.MATCH_DEFAULT_ONLY).activityInfo.applicationInfo.packageName; 43 | } catch (Exception e) { 44 | return null; // 日了狗了 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/util/SoftInputManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.util; 20 | 21 | import android.content.Context; 22 | import android.view.View; 23 | import android.view.inputmethod.InputMethodManager; 24 | 25 | public class SoftInputManager { 26 | 27 | private final View view; 28 | private final InputMethodManager imm; 29 | 30 | private SoftInputManager(View view, InputMethodManager imm) { 31 | this.view = view; 32 | this.imm = imm; 33 | } 34 | 35 | public static SoftInputManager from(View view) { 36 | return new SoftInputManager(view, 37 | (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE)); 38 | } 39 | 40 | public void show() { 41 | imm.showSoftInput(view, 0); 42 | } 43 | 44 | public void hide() { 45 | imm.hideSoftInputFromWindow(view.getWindowToken(), 0); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/util/UpdateUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.util; 20 | 21 | import android.content.ActivityNotFoundException; 22 | import android.content.Context; 23 | import android.content.Intent; 24 | import android.net.Uri; 25 | import android.support.v7.app.AlertDialog; 26 | import android.text.TextUtils; 27 | 28 | import im.fir.sdk.FIR; 29 | import im.fir.sdk.callback.VersionCheckCallback; 30 | import im.fir.sdk.version.AppVersion; 31 | import ooo.oxo.apps.materialize.BuildConfig; 32 | import ooo.oxo.apps.materialize.R; 33 | 34 | public class UpdateUtil { 35 | 36 | public static void checkForUpdateAndPrompt(Context context) { 37 | //noinspection PointlessBooleanExpression 38 | if (!BuildConfig.FIR_OTA_ENABLED) { 39 | return; 40 | } 41 | 42 | FIR.checkForUpdateInFIR(BuildConfig.FIR_API_TOKEN, new VersionCheckCallback() { 43 | @Override 44 | public void onSuccess(AppVersion version, boolean b) { 45 | if (version.getVersionCode() > BuildConfig.VERSION_CODE) { 46 | promptUpdate(context, version); 47 | } 48 | } 49 | }); 50 | } 51 | 52 | private static void promptUpdate(Context context, AppVersion version) { 53 | new AlertDialog.Builder(context) 54 | .setTitle(context.getString(R.string.update_available, version.getVersionName())) 55 | .setMessage(TextUtils.isEmpty(version.getChangeLog()) 56 | ? null 57 | : version.getChangeLog()) 58 | .setNegativeButton(R.string.update_cancel, null) 59 | .setPositiveButton(R.string.update_confirm, (dialog, which) -> { 60 | try { 61 | context.startActivity(new Intent(Intent.ACTION_VIEW, 62 | Uri.parse(version.getUpdateUrl()))); 63 | } catch (ActivityNotFoundException e) { 64 | // 狗带 65 | } 66 | }) 67 | .show(); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/ooo/oxo/apps/materialize/widget/CompositeView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Materialize - Materialize all those not material 3 | * Copyright (C) 2015 XiNGRZ 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package ooo.oxo.apps.materialize.widget; 20 | 21 | import android.content.Context; 22 | import android.graphics.Bitmap; 23 | import android.graphics.drawable.Drawable; 24 | import android.util.AttributeSet; 25 | import android.widget.ImageView; 26 | 27 | import ooo.oxo.apps.materialize.graphics.CompositeDrawable; 28 | 29 | public class CompositeView extends ImageView { 30 | 31 | private CompositeDrawable composite; 32 | 33 | public CompositeView(Context context) { 34 | this(context, null); 35 | } 36 | 37 | public CompositeView(Context context, AttributeSet attrs) { 38 | this(context, attrs, 0); 39 | } 40 | 41 | public CompositeView(Context context, AttributeSet attrs, int defStyleAttr) { 42 | super(context, attrs, defStyleAttr); 43 | setImageDrawable(composite = new CompositeDrawable(getResources())); 44 | } 45 | 46 | public void setImage(Bitmap image) { 47 | composite.setSource(image); 48 | } 49 | 50 | public void setShape(CompositeDrawable.Shape shape) { 51 | composite.setShape(shape); 52 | } 53 | 54 | public void setPadding(float padding) { 55 | composite.setPadding(padding); 56 | } 57 | 58 | public void setCanvasBackground(Drawable background) { 59 | composite.setBackground(background); 60 | } 61 | 62 | public CompositeDrawable getComposite() { 63 | return composite; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi-v18/stencil_round_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-anydpi-v18/stencil_round_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi-v18/stencil_round_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-anydpi-v18/stencil_round_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi-v18/stencil_round_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-anydpi-v18/stencil_round_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi-v18/stencil_square_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-anydpi-v18/stencil_square_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi-v18/stencil_square_dogear_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-anydpi-v18/stencil_square_dogear_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi-v18/stencil_square_dogear_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-anydpi-v18/stencil_square_dogear_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi-v18/stencil_square_dogear_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-anydpi-v18/stencil_square_dogear_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi-v18/stencil_square_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-anydpi-v18/stencil_square_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi-v18/stencil_square_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-anydpi-v18/stencil_square_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/stencil_round_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-hdpi/stencil_round_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/stencil_round_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-hdpi/stencil_round_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/stencil_round_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-hdpi/stencil_round_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/stencil_square_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-hdpi/stencil_square_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/stencil_square_dogear_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-hdpi/stencil_square_dogear_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/stencil_square_dogear_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-hdpi/stencil_square_dogear_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/stencil_square_dogear_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-hdpi/stencil_square_dogear_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/stencil_square_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-hdpi/stencil_square_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/stencil_square_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-hdpi/stencil_square_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/stencil_round_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-mdpi/stencil_round_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/stencil_round_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-mdpi/stencil_round_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/stencil_round_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-mdpi/stencil_round_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/stencil_square_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-mdpi/stencil_square_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/stencil_square_dogear_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-mdpi/stencil_square_dogear_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/stencil_square_dogear_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-mdpi/stencil_square_dogear_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/stencil_square_dogear_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-mdpi/stencil_square_dogear_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/stencil_square_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-mdpi/stencil_square_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/stencil_square_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-mdpi/stencil_square_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/web_hi_res_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-nodpi/web_hi_res_512.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/stencil_round_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xhdpi/stencil_round_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/stencil_round_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xhdpi/stencil_round_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/stencil_round_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xhdpi/stencil_round_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/stencil_square_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xhdpi/stencil_square_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/stencil_square_dogear_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xhdpi/stencil_square_dogear_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/stencil_square_dogear_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xhdpi/stencil_square_dogear_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/stencil_square_dogear_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xhdpi/stencil_square_dogear_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/stencil_square_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xhdpi/stencil_square_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/stencil_square_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xhdpi/stencil_square_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/stencil_round_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xxhdpi/stencil_round_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/stencil_round_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xxhdpi/stencil_round_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/stencil_round_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xxhdpi/stencil_round_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/stencil_square_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xxhdpi/stencil_square_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/stencil_square_dogear_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xxhdpi/stencil_square_dogear_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/stencil_square_dogear_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xxhdpi/stencil_square_dogear_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/stencil_square_dogear_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xxhdpi/stencil_square_dogear_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/stencil_square_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xxhdpi/stencil_square_fore.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/stencil_square_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxoooo/materialize/6e2cc62efb6aba0002393b2636b82c1b8a61a919/app/src/main/res/drawable-xxhdpi/stencil_square_mask.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_forward_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_close_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_filter_list_24dp.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 24 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_more_vert_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/about_activity.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 35 | 36 | 43 | 44 | 52 | 53 | 66 | 67 | 75 | 76 | 84 | 85 | 94 | 95 | 96 | 97 | 104 | 105 | 106 | 107 | 108 | 109 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /app/src/main/res/layout/about_header.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/about_library_item.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | 37 | 38 | 48 | 49 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adjust_activity.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 30 | 31 | 34 | 35 | 38 | 39 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 52 | 60 | 61 | 68 | 69 | 75 | 76 | 84 | 85 | 91 | 92 | 101 | 102 | 103 | 104 | 112 | 113 | 119 | 120 | 128 | 129 | 134 | 135 | 140 | 141 | 146 | 147 | 152 | 153 | 158 | 159 | 160 | 161 | 167 | 168 | 176 | 177 | 183 | 184 | 191 | 192 | 198 | 199 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 221 | 222 | 226 | 227 |