├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── be │ │ │ └── omnuzel │ │ │ └── patternplaceholderapp │ │ │ └── MainActivity.java │ └── res │ │ ├── layout │ │ └── activity_main.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 │ │ ├── patternplaceholder-patterns.png │ │ ├── patternplaceholder-textalign.png │ │ └── patternplaceholder-title.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── be │ └── omnuzel │ └── patternplaceholderapp │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── patternplaceholder ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── be │ │ └── omnuzel │ │ └── patternplaceholder │ │ └── InstrumentedBuilderValidityTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── be │ │ │ └── omnuzel │ │ │ └── patternplaceholder │ │ │ ├── BitmapFetcher.java │ │ │ ├── MaterialColor.java │ │ │ ├── PatternPlaceholder.java │ │ │ ├── PatternPlaceholderAsyncTask.java │ │ │ └── RandomColor.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── be │ └── omnuzel │ └── patternplaceholder │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/android,intellij 3 | 4 | ### Android ### 5 | # Built application files 6 | *.apk 7 | *.ap_ 8 | 9 | # Files for the ART/Dalvik VM 10 | *.dex 11 | 12 | # Java class files 13 | *.class 14 | 15 | # Generated files 16 | bin/ 17 | gen/ 18 | out/ 19 | 20 | # Gradle files 21 | .gradle/ 22 | build/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # Intellij 40 | *.iml 41 | .idea/workspace.xml 42 | .idea/tasks.xml 43 | .idea/libraries 44 | 45 | # Keystore files 46 | *.jks 47 | 48 | # External native build folder generated in Android Studio 2.2 and later 49 | .externalNativeBuild 50 | 51 | ### Android Patch ### 52 | gen-external-apklibs 53 | 54 | 55 | ### Intellij ### 56 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 57 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 58 | 59 | # User-specific stuff: 60 | 61 | # Sensitive or high-churn files: 62 | .idea/dataSources/ 63 | .idea/dataSources.ids 64 | .idea/dataSources.xml 65 | .idea/dataSources.local.xml 66 | .idea/sqlDataSources.xml 67 | .idea/dynamic.xml 68 | .idea/uiDesigner.xml 69 | 70 | # Gradle: 71 | .idea/gradle.xml 72 | 73 | # Mongo Explorer plugin: 74 | .idea/mongoSettings.xml 75 | 76 | ## File-based project format: 77 | *.iws 78 | 79 | ## Plugin-specific files: 80 | 81 | # IntelliJ 82 | /out/ 83 | 84 | # mpeltonen/sbt-idea plugin 85 | .idea_modules/ 86 | 87 | # JIRA plugin 88 | atlassian-ide-plugin.xml 89 | 90 | # Crashlytics plugin (for Android Studio and IntelliJ) 91 | com_crashlytics_export_strings.xml 92 | crashlytics.properties 93 | crashlytics-build.properties 94 | fabric.properties 95 | 96 | ### Intellij Patch ### 97 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 98 | 99 | # *.iml 100 | # modules.xml 101 | # .idea/misc.xml 102 | # *.ipr -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![alt text](https://github.com/Oyzuu/PatternPlaceholder-Android/blob/master/app/src/main/res/mipmap-xxxhdpi/patternplaceholder-title.png "Pattern Placeholder for Android") 3 | 4 | A bitmap generator with numerous tiling options. 5 | 6 | ## Features 7 | * Pseudo random bitmap generation 8 | * Synchronous and asynchronous generation 9 | * Caching for huge and / or dense images 10 | * All the material colors at hand with swatches or individual color getters 11 | 12 | ## Installation 13 | Via Maven... 14 | ```xml 15 | 16 | be.omnuzel.patternplaceholder 17 | patternplaceholder 18 | 1.0.0 19 | pom 20 | 21 | ``` 22 | ... or Gradle, by adding this repository in your project `build.gradle` 23 | ```gradle 24 | maven { 25 | url 'https://dl.bintray.com/oyzuu/maven/' 26 | } 27 | ``` 28 | and this in your app `build.gradle` 29 | ```gradle 30 | compile 'be.omnuzel.patternplaceholder:patternplaceholder:1.0.0' 31 | ``` 32 | 33 | ## How-to 34 | Instantiate a new `PatternPlaceholder.Builder` with a context and generate. It will, by default, generate a 3 by 3 random gray mozaic. 35 | ```java 36 | Bitmap bitmap = new PatternPlaceholder.Builder(this).generate(); 37 | ``` 38 | 39 | ![alt text](https://github.com/Oyzuu/PatternPlaceholder-Android/blob/master/app/src/main/res/mipmap-xxxhdpi/patternplaceholder-textalign.png "text align example") 40 | 41 | Specify the pattern, number of tiles, bitmap size, overdrawn text, etc... 42 | ```java 43 | Bitmap bitmap = new PatternPlaceholder.Builder(this) 44 | .setSize(300, 300) 45 | .setTilesPerSide(3) 46 | .setPatternType(PatternPlaceholder.PatternType.RANDOM_TRIANGLES) 47 | .setText("User") 48 | .setTextColor(Color.WHITE) 49 | .setTextAlign(PatternPlaceholder.TextAlign.LOWER_RIGHT) 50 | .generate(); 51 | ``` 52 | 53 | ![alt text](https://github.com/Oyzuu/PatternPlaceholder-Android/blob/master/app/src/main/res/mipmap-xxxhdpi/patternplaceholder-patterns.png "patterns example") 54 | 55 | Use [any material design color](https://material.google.com/style/color.html) individually or get corresponding swatch with `MaterialColor.getColorForValue(int, int)` and `getSwatch(int)` 56 | 57 | For asynchronous loading, use `generate(PatternGeneratorAsyncListener)` or `generate(ImageView)`. 58 | With a context provided as listener, `onGenerated(Bitmap)` will be called on completion. 59 | ```java 60 | new PatternPlaceholder.Builder(this) 61 | // the complete swatch from 50 to 900 62 | .setPalette(MaterialColor.getSwatch(MaterialColor.Color.LIGHT_BLUE)) 63 | .generate(yourImageView); 64 | // or generate(PatternGeneratorAsyncListener) 65 | ``` 66 | 67 | Or use `RandomColor` for various random coloring (i.e. : light greys, dark greys or any randomized color) 68 | ```java 69 | new PatternPlaceholder.Builder(this) 70 | // ALL, LIGHT_GREY, MEDIUM_GREY, DARK_GREY, GREY 71 | .setColorGenerationType(RandomColor.ColorType.ALL) 72 | .generate(yourImageView); 73 | ``` 74 | 75 | ### Builder methods 76 | 77 | method | description 78 | --- | --- 79 | setSize(*int*, *int*) | Set the width and height of the bitmap 80 | setTilesPerSide(*int*) | Set the number of tiles, strips, scales or lines, depending on pattern type 81 | setPalette(*@Nullable int[]*) | Set the color palette used for generation (if null, will use colorGenerationType) 82 | setColorGenerationType(*@RandomColor.ColorType int*) | Set the color generation for RandomColor (warning on non-constants, GREY by default) 83 | setPatternType(*@PatternType int*) | Set the bitmap pattern (warning on non-constants, SQUARES by default) 84 | setSeed(*long*) | Set the seed for the Random instance used in triangles and RandomColor generation 85 | setText(*String*) | The text to be drawn on top of the bitmap (won't be called if the string is empty after whitespace trimming) 86 | setTextColor(*int*) | The color of drawn text 87 | setTextAlign(*@TextAlign int*) | The text alignment (warning on non-constants, CENTER by default) 88 | withCacheEnabled(*boolean*) | Enable caching (should be reserved for large and / or dense bitmaps) 89 | generate() | Synchronous, return a bitmap 90 | generate(*PatternGeneratorAsyncListener*) | Asynchronous, onGenerated(*Bitmap*) will be called on completion 91 | generate(*ImageView*) | Asynchronous, generate and load the bitmap into given ImageView 92 | 93 | ### RandomColor methods 94 | 95 | method | description 96 | --- | --- 97 | get(*@Nullable int[]*, *@ColorType int*, *@NonNull Random*) | Return a color integer, picked randomly from the palette or, if said palette is null, from any method corresponding to given ColorType 98 | getColor(*@NonNull Random*) | Return a random color, range : red[0-255], green[0-255], blue[0-255] 99 | getGrey(*@NonNull Random*) | Return a random grey value, range : [0-255] 100 | getLightGrey(*@NonNull Random*) | Return a random light grey value, range : [155-255] 101 | getMediumGrey(*@NonNull Random*) | Return a random medium grey value, range : [100-200] 102 | getRandomDarkGrey(*@NonNull Random*) | Return a random dark grey value, range : [0-100] 103 | 104 | ### MaterialColor methods 105 | method | description 106 | --- | --- 107 | getSwatch(*@MaterialColor.Color int*) | Return a palette for given material color (material values from 50 to 900) 108 | getColorForValue(*@MaterialColor.Color int*, *int*) | Return the corresponding material color for given value 109 | 110 | Swatches with values can befound here : [https://material.google.com/style/color.html](https://material.google.com/style/color.html) 111 | 112 | *** 113 | 114 | Special thanks to Jean-Bernard Collet for guidance and advice. Find him on [LinkedIn](https://www.linkedin.com/in/jean-bernard-collet-a0176418/en ) 115 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.0" 6 | defaultConfig { 7 | applicationId "be.omnuzel.patternplaceholder" 8 | minSdkVersion 17 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.0.0' 28 | compile project(':patternplaceholder') 29 | testCompile 'junit:junit:4.12' 30 | } 31 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/isdc/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/be/omnuzel/patternplaceholderapp/MainActivity.java: -------------------------------------------------------------------------------- 1 | package be.omnuzel.patternplaceholderapp; 2 | 3 | import android.graphics.Bitmap; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.MotionEvent; 7 | import android.widget.ImageView; 8 | import android.widget.RelativeLayout; 9 | 10 | import be.omnuzel.patternplaceholder.MaterialColor; 11 | import be.omnuzel.patternplaceholder.PatternPlaceholder; 12 | 13 | public class MainActivity extends AppCompatActivity { 14 | 15 | private ImageView mImageView1, mImageView2, mImageView3, mImageView4; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_main); 21 | 22 | mImageView1 = (ImageView) findViewById(R.id.image_view_1); 23 | mImageView2 = (ImageView) findViewById(R.id.image_view_2); 24 | mImageView3 = (ImageView) findViewById(R.id.image_view_3); 25 | mImageView4 = (ImageView) findViewById(R.id.image_view_4); 26 | } 27 | 28 | @Override 29 | public boolean onTouchEvent(MotionEvent event) { 30 | 31 | Bitmap bitmap; 32 | 33 | int patternType = PatternPlaceholder.PatternType.SCALES; 34 | int[] palette = new int[]{ 35 | MaterialColor.getColorForValue(MaterialColor.Color.BLUE, 500), 36 | MaterialColor.getColorForValue(MaterialColor.Color.BLUE, 200), 37 | MaterialColor.getColorForValue(MaterialColor.Color.BLUE, 800) 38 | }; 39 | 40 | RelativeLayout layout = (RelativeLayout) findViewById(R.id.activity_main); 41 | 42 | new PatternPlaceholder.Builder(this) 43 | .generate(mImageView1); 44 | 45 | new PatternPlaceholder.Builder(this).generate(mImageView2); 46 | 47 | PatternPlaceholder.Builder builder3 = new PatternPlaceholder.Builder(this); 48 | builder3.generate(mImageView3); 49 | 50 | PatternPlaceholder.Builder builder4 = new PatternPlaceholder.Builder(this); 51 | builder4.generate(mImageView4); 52 | 53 | return super.onTouchEvent(event); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 19 | 20 | 25 | 26 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oyzuu/PatternPlaceholder-Android/8a22ef666962bdea1b4ff4a014f440b6b94843c5/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oyzuu/PatternPlaceholder-Android/8a22ef666962bdea1b4ff4a014f440b6b94843c5/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oyzuu/PatternPlaceholder-Android/8a22ef666962bdea1b4ff4a014f440b6b94843c5/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oyzuu/PatternPlaceholder-Android/8a22ef666962bdea1b4ff4a014f440b6b94843c5/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oyzuu/PatternPlaceholder-Android/8a22ef666962bdea1b4ff4a014f440b6b94843c5/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/patternplaceholder-patterns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oyzuu/PatternPlaceholder-Android/8a22ef666962bdea1b4ff4a014f440b6b94843c5/app/src/main/res/mipmap-xxxhdpi/patternplaceholder-patterns.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/patternplaceholder-textalign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oyzuu/PatternPlaceholder-Android/8a22ef666962bdea1b4ff4a014f440b6b94843c5/app/src/main/res/mipmap-xxxhdpi/patternplaceholder-textalign.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/patternplaceholder-title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oyzuu/PatternPlaceholder-Android/8a22ef666962bdea1b4ff4a014f440b6b94843c5/app/src/main/res/mipmap-xxxhdpi/patternplaceholder-title.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | PatternPlaceholder 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/be/omnuzel/patternplaceholderapp/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package be.omnuzel.patternplaceholderapp; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.test.mock.MockContext; 6 | 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | import static org.junit.Assert.assertTrue; 11 | 12 | /** 13 | * Example local unit test, which will execute on the development machine (host). 14 | * 15 | * @see Testing documentation 16 | */ 17 | public class ExampleUnitTest { 18 | Bitmap bitmap; 19 | 20 | @Test 21 | public void addition_isCorrect() throws Exception { 22 | assertEquals(4, 2 + 2); 23 | 24 | Context context = new MockContext(); 25 | int DESIRED_WIDTH = 150; 26 | int DESIRED_HEIGHT = 150; 27 | 28 | bitmap = new PatternPlaceholder.Builder(context) 29 | .setSize(DESIRED_WIDTH, DESIRED_HEIGHT) 30 | .generate(); 31 | 32 | assertTrue(bitmap.getWidth() == DESIRED_WIDTH && bitmap.getHeight() == DESIRED_HEIGHT); 33 | } 34 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.2' 9 | classpath "com.github.dcendents:android-maven-gradle-plugin:1.5" 10 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.5' 11 | 12 | // NOTE: Do not place your application dependencies here; they belong 13 | // in the individual module build.gradle files 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | jcenter() 20 | } 21 | } 22 | 23 | task clean(type: Delete) { 24 | delete rootProject.buildDir 25 | } 26 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Oyzuu/PatternPlaceholder-Android/8a22ef666962bdea1b4ff4a014f440b6b94843c5/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /patternplaceholder/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /patternplaceholder/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.jfrog.bintray' 3 | apply plugin: 'com.github.dcendents.android-maven' 4 | 5 | android { 6 | compileSdkVersion 25 7 | buildToolsVersion "25.0.0" 8 | 9 | defaultConfig { 10 | minSdkVersion 17 11 | targetSdkVersion 25 12 | versionCode 1 13 | versionName "1.0.0" 14 | 15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 16 | 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | 26 | dependencies { 27 | compile fileTree(dir: 'libs', include: ['*.jar']) 28 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 29 | exclude group: 'com.android.support', module: 'support-annotations' 30 | }) 31 | compile 'com.android.support:appcompat-v7:25.0.0' 32 | testCompile 'junit:junit:4.12' 33 | } 34 | 35 | group = 'be.omnuzel.patternplaceholder' 36 | version = '1.0.0' 37 | 38 | bintray { 39 | user = System.getenv('BINTRAY_USER') 40 | key = System.getenv('BINTRAY_APIKEY') 41 | // jFrog plugin must be declared for this line to work 42 | configurations = ['archives'] 43 | // Package info for BinTray 44 | pkg { 45 | repo = 'maven' 46 | name = 'be.omnuzel.patternplaceholder' 47 | licenses = ['Apache-2.0'] 48 | vcsUrl = 'https://github.com/Oyzuu/PatternPlaceholder-Android.git' 49 | 50 | version { 51 | name = '1.0.0' 52 | desc = '1.0.0 initial upload' 53 | released = new Date() 54 | vcsTag = '1.0.0' 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /patternplaceholder/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/isdc/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /patternplaceholder/src/androidTest/java/be/omnuzel/patternplaceholder/InstrumentedBuilderValidityTest.java: -------------------------------------------------------------------------------- 1 | package be.omnuzel.patternplaceholder; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.support.test.InstrumentationRegistry; 6 | import android.support.test.runner.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.assertTrue; 12 | 13 | /** 14 | * Instrumentation test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class InstrumentedBuilderValidityTest { 20 | 21 | @Test 22 | public void nonNullBitmap() throws Exception { 23 | // Context of the app under test. 24 | Context appContext = InstrumentationRegistry.getTargetContext(); 25 | 26 | Bitmap bitmap = new PatternPlaceholder.Builder(appContext) 27 | .generate(); 28 | 29 | assertTrue(bitmap != null); 30 | } 31 | 32 | @Test 33 | public void correctSizeBitmap() throws Exception { 34 | // Context of the app under test. 35 | Context appContext = InstrumentationRegistry.getTargetContext(); 36 | 37 | int DESIRED_WIDTH = 150; 38 | int DESIRED_HEIGHT = 150; 39 | 40 | Bitmap bitmap = new PatternPlaceholder.Builder(appContext) 41 | .setSize(DESIRED_WIDTH, DESIRED_HEIGHT) 42 | .generate(); 43 | 44 | assertTrue(bitmap.getWidth() == DESIRED_WIDTH && bitmap.getHeight() == DESIRED_HEIGHT); 45 | } 46 | 47 | @Test(expected = IllegalArgumentException.class) 48 | public void WithInvalidSize() { 49 | Context appContext = InstrumentationRegistry.getTargetContext(); 50 | 51 | Bitmap bitmap = new PatternPlaceholder.Builder(appContext) 52 | .setSize(-1, -1) 53 | .generate(); 54 | } 55 | 56 | @Test(expected = ArrayIndexOutOfBoundsException.class) 57 | public void withArrayOfZeroSize() { 58 | Context appContext = InstrumentationRegistry.getTargetContext(); 59 | 60 | Bitmap bitmap = new PatternPlaceholder.Builder(appContext) 61 | .setPalette(new int[]{}) 62 | .generate(); 63 | } 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /patternplaceholder/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /patternplaceholder/src/main/java/be/omnuzel/patternplaceholder/BitmapFetcher.java: -------------------------------------------------------------------------------- 1 | package be.omnuzel.patternplaceholder; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.os.Environment; 7 | import android.util.Log; 8 | 9 | import java.io.BufferedInputStream; 10 | import java.io.File; 11 | import java.io.FileInputStream; 12 | import java.io.FileOutputStream; 13 | import java.io.IOException; 14 | 15 | import static android.os.Environment.isExternalStorageRemovable; 16 | 17 | /** 18 | * Created by De Cooman Sammy on 18/11/16. 19 | */ 20 | 21 | public class BitmapFetcher { 22 | 23 | private final File cacheDir; 24 | 25 | public BitmapFetcher(Context context) { 26 | Log.i("BitmapFetcher init", ""); 27 | 28 | cacheDir = getCacheDirectory(context, "images"); 29 | createImageCacheDir(); 30 | } 31 | 32 | public void addBitmapToCache(String fileName, Bitmap bitmap) { 33 | FileOutputStream out = null; 34 | 35 | try { 36 | out = new FileOutputStream(new File(cacheDir, fileName + ".png")); 37 | bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); 38 | out.close(); 39 | } catch (IOException e) { 40 | e.printStackTrace(); 41 | } 42 | } 43 | 44 | public Bitmap getBitmapFromCache(String fileName) { 45 | BufferedInputStream stream = null; 46 | try { 47 | stream = new BufferedInputStream(new FileInputStream(new File(cacheDir, fileName + ".png"))); 48 | Bitmap bitmap = BitmapFactory.decodeStream(stream); 49 | stream.close(); 50 | return bitmap; 51 | } catch (IOException e) { 52 | Log.i("BITMAP-FETCHER", "File not found : " + fileName + ".png"); 53 | return null; 54 | } 55 | } 56 | 57 | private File getCacheDirectory(Context context, String uniqueName) { 58 | 59 | final String cachePath = 60 | Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || 61 | !isExternalStorageRemovable() ? context.getExternalCacheDir().getPath() : 62 | context.getCacheDir().getPath(); 63 | 64 | return new File(cachePath + File.separator + uniqueName); 65 | } 66 | 67 | private boolean createImageCacheDir() { 68 | if (!cacheDir.exists()) { 69 | cacheDir.mkdirs(); 70 | } 71 | 72 | return true; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /patternplaceholder/src/main/java/be/omnuzel/patternplaceholder/MaterialColor.java: -------------------------------------------------------------------------------- 1 | package be.omnuzel.patternplaceholder; 2 | 3 | import android.support.annotation.IntDef; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | /** 9 | * Created by De Cooman Sammy on 16/11/16. 10 | *

11 | * All the material colors easily accessible. 12 | * 13 | * @see https://material.google.com/style/color.html 14 | */ 15 | public final class MaterialColor { 16 | 17 | @Retention(RetentionPolicy.SOURCE) 18 | @IntDef({ 19 | Color.RED, 20 | Color.PINK, 21 | Color.PURPLE, 22 | Color.DEEP_PURPLE, 23 | Color.INDIGO, 24 | Color.BLUE, 25 | Color.LIGHT_BLUE, 26 | Color.CYAN, 27 | Color.TEAL, 28 | Color.GREEN, 29 | Color.LIGHT_GREEN, 30 | Color.LIME, 31 | Color.YELLOW, 32 | Color.AMBER, 33 | Color.ORANGE, 34 | Color.DEEP_ORANGE, 35 | Color.BROWN, 36 | Color.GREY, 37 | Color.BLUE_GREY}) 38 | public @interface Color { 39 | int RED = 0; 40 | int PINK = 1; 41 | int PURPLE = 2; 42 | int DEEP_PURPLE = 3; 43 | int INDIGO = 4; 44 | int BLUE = 5; 45 | int LIGHT_BLUE = 6; 46 | int CYAN = 7; 47 | int TEAL = 8; 48 | int GREEN = 9; 49 | int LIGHT_GREEN = 10; 50 | int LIME = 11; 51 | int YELLOW = 12; 52 | int AMBER = 13; 53 | int ORANGE = 14; 54 | int DEEP_ORANGE = 15; 55 | int BROWN = 16; 56 | int GREY = 17; 57 | int BLUE_GREY = 18; 58 | } 59 | 60 | public static int[] getSwatch(@Color int swatchName) { 61 | switch (swatchName) { 62 | case Color.RED: 63 | return new int[]{ 64 | 0xFFFFEBEE, 0xFFFFCDD2, 0xFFEF9A9A, 0xFFE57373, 0xFFEF5350, 65 | 0xFFF44336, 0xFFE53935, 0xFFD32F2F, 0xFFC62828, 0xFFB71C1C 66 | }; 67 | case Color.PINK: 68 | return new int[]{ 69 | 0xFFFCE4EC, 0xFFF8BBD0, 0xFFF48FB1, 0xFFF06292, 0xFFEC407A, 70 | 0xFFE91E63, 0xFFD81B60, 0xFFC2185B, 0xFFAD1457, 0xFF880E4F 71 | }; 72 | case Color.PURPLE: 73 | return new int[]{ 74 | 0xFFF3E5F5, 0xFFE1BEE7, 0xFFCE93D8, 0xFFBA68C8, 0xFFAB47BC, 75 | 0xFF9C27B0, 0xFF8E24AA, 0xFF7B1FA2, 0xFF6A1B9A, 0xFF4A148C 76 | }; 77 | case Color.DEEP_PURPLE: 78 | return new int[]{ 79 | 0xFFEDE7F6, 0xFFD1C4E9, 0xFFB39DDB, 0xFF9575CD, 0xFF7E57C2, 80 | 0xFF673AB7, 0xFF5E35B1, 0xFF512DA8, 0xFF4527A0, 0xFF311B92 81 | }; 82 | case Color.INDIGO: 83 | return new int[]{ 84 | 0xFFE8EAF6, 0xFFC5CAE9, 0xFF9FA8DA, 0xFF7986CB, 0xFF5C6BC0, 85 | 0xFF3F51B5, 0xFF3949AB, 0xFF303F9F, 0xFF283593, 0xFF1A237E 86 | }; 87 | case Color.BLUE: 88 | return new int[]{ 89 | 0xFFE3F2FD, 0xFFBBDEFB, 0xFF90CAF9, 0xFF64B5F6, 0xFF42A5F5, 90 | 0xFF2196F3, 0xFF1E88E5, 0xFF1976D2, 0xFF1565C0, 0xFF0D47A1 91 | }; 92 | case Color.LIGHT_BLUE: 93 | return new int[]{ 94 | 0xFFE1F5FE, 0xFFB3E5FC, 0xFF81D4FA, 0xFF4FC3F7, 0xFF29B6F6, 95 | 0xFF03A9F4, 0xFF039BE5, 0xFF0288D1, 0xFF0277BD, 0xFF01579B 96 | }; 97 | case Color.CYAN: 98 | return new int[]{ 99 | 0xFFE0F7FA, 0xFFB2EBF2, 0xFF80DEEA, 0xFF4DD0E1, 0xFF26C6DA, 100 | 0xFF00BCD4, 0xFF00ACC1, 0xFF0097A7, 0xFF00838F, 0xFF006064 101 | }; 102 | case Color.TEAL: 103 | return new int[]{ 104 | 0xFFE0F2F1, 0xFFB2DFDB, 0xFF80CBC4, 0xFF4DB6AC, 0xFF26A69A, 105 | 0xFF009688, 0xFF00897B, 0xFF00796B, 0xFF00695C, 0xFF004D40 106 | }; 107 | case Color.GREEN: 108 | return new int[]{ 109 | 0xFFE8F5E9, 0xFFC8E6C9, 0xFFA5D6A7, 0xFF81C784, 0xFF66BB6A, 110 | 0xFF4CAF50, 0xFF43A047, 0xFF388E3C, 0xFF2E7D32, 0xFF1B5E20 111 | }; 112 | case Color.LIGHT_GREEN: 113 | return new int[]{ 114 | 0xFFF1F8E9, 0xFFDCEDC8, 0xFFC5E1A5, 0xFFAED581, 0xFF9CCC65, 115 | 0xFF8BC34A, 0xFF7CB342, 0xFF689F38, 0xFF558B2F, 0xFF33691E 116 | }; 117 | case Color.LIME: 118 | return new int[]{ 119 | 0xFFF9FBE7, 0xFFF0F4C3, 0xFFE6EE9C, 0xFFDCE775, 0xFFD4E157, 120 | 0xFFCDDC39, 0xFFC0CA33, 0xFFAFB42B, 0xFF9E9D24, 0xFF827717 121 | }; 122 | case Color.YELLOW: 123 | return new int[]{ 124 | 0xFFFFFDE7, 0xFFFFF9C4, 0xFFFFF59D, 0xFFFFF176, 0xFFFFEE58, 125 | 0xFFFFEB3B, 0xFFFDD835, 0xFFFBC02D, 0xFFF9A825, 0xFFF57F17 126 | }; 127 | case Color.AMBER: 128 | return new int[]{ 129 | 0xFFFFF8E1, 0xFFFFECB3, 0xFFFFE082, 0xFFFFD54F, 0xFFFFCA28, 130 | 0xFFFFC107, 0xFFFFB300, 0xFFFFA000, 0xFFFF8F00, 0xFFFF6F00 131 | }; 132 | case Color.ORANGE: 133 | return new int[]{ 134 | 0xFFFFF3E0, 0xFFFFE0B2, 0xFFFFCC80, 0xFFFFB74D, 0xFFFFA726, 135 | 0xFFFF9800, 0xFFFB8C00, 0xFFF57C00, 0xFFEF6C00, 0xFFE65100 136 | }; 137 | case Color.DEEP_ORANGE: 138 | return new int[]{ 139 | 0xFFFBE9E7, 0xFFFFCCBC, 0xFFFFAB91, 0xFFFF8A65, 0xFFFF7043, 140 | 0xFFFF5722, 0xFFF4511E, 0xFFE64A19, 0xFFD84315, 0xFFBF360C 141 | }; 142 | case Color.BROWN: 143 | return new int[]{ 144 | 0xFFEFEBE9, 0xFFD7CCC8, 0xFFBCAAA4, 0xFFA1887F, 0xFF8D6E63, 145 | 0xFF795548, 0xFF6D4C41, 0xFF5D4037, 0xFF4E342E, 0xFF3E2723 146 | }; 147 | case Color.GREY: 148 | return new int[]{ 149 | 0xFFFAFAFA, 0xFFF5F5F5, 0xFFEEEEEE, 0xFFE0E0E0, 0xFFBDBDBD, 150 | 0xFF9E9E9E, 0xFF757575, 0xFF616161, 0xFF424242, 0xFF212121 151 | }; 152 | case Color.BLUE_GREY: 153 | return new int[]{ 154 | 0xFFECEFF1, 0xFFCFD8DC, 0xFFB0BEC5, 0xFF90A4AE, 0xFF78909C, 155 | 0xFF607D8B, 0xFF546E7A, 0xFF455A64, 0xFF37474F, 0xFF263238 156 | }; 157 | default: 158 | return new int[]{ 159 | 0xFFFAFAFA, 0xFFF5F5F5, 0xFFEEEEEE, 0xFFE0E0E0, 0xFFBDBDBD, 160 | 0xFF9E9E9E, 0xFF757575, 0xFF616161, 0xFF424242, 0xFF212121 161 | }; 162 | } 163 | } 164 | 165 | public static int getColorForValue(@MaterialColor.Color int colorName, int value) { 166 | switch (value) { 167 | case 50: 168 | return getSwatch(colorName)[0]; 169 | case 100: 170 | return getSwatch(colorName)[1]; 171 | case 200: 172 | return getSwatch(colorName)[2]; 173 | case 300: 174 | return getSwatch(colorName)[3]; 175 | case 400: 176 | return getSwatch(colorName)[4]; 177 | case 500: 178 | return getSwatch(colorName)[5]; 179 | case 600: 180 | return getSwatch(colorName)[6]; 181 | case 700: 182 | return getSwatch(colorName)[7]; 183 | case 800: 184 | return getSwatch(colorName)[8]; 185 | case 900: 186 | return getSwatch(colorName)[9]; 187 | default: 188 | return getSwatch(colorName)[5]; 189 | } 190 | } 191 | 192 | } 193 | -------------------------------------------------------------------------------- /patternplaceholder/src/main/java/be/omnuzel/patternplaceholder/PatternPlaceholder.java: -------------------------------------------------------------------------------- 1 | package be.omnuzel.patternplaceholder; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Canvas; 7 | import android.graphics.Color; 8 | import android.graphics.Paint; 9 | import android.graphics.Path; 10 | import android.graphics.Rect; 11 | import android.graphics.Typeface; 12 | import android.os.AsyncTask; 13 | import android.support.annotation.ColorInt; 14 | import android.support.annotation.IntDef; 15 | import android.support.annotation.IntRange; 16 | import android.support.annotation.NonNull; 17 | import android.support.annotation.Nullable; 18 | import android.support.annotation.Size; 19 | import android.util.Log; 20 | import android.widget.ImageView; 21 | 22 | import java.lang.annotation.Retention; 23 | import java.lang.annotation.RetentionPolicy; 24 | import java.util.Arrays; 25 | import java.util.Random; 26 | 27 | /** 28 | * Created by De Cooman Sammy on 11/11/16. 29 | */ 30 | 31 | public final class PatternPlaceholder { 32 | 33 | // Constants used for pattern selection 34 | @Retention(RetentionPolicy.SOURCE) 35 | @IntDef({ 36 | PatternType.SQUARES, 37 | PatternType.VERTICAL_LINES, 38 | PatternType.HORIZONTAL_LINES, 39 | PatternType.SCALES, 40 | PatternType.RANDOM_TRIANGLES}) 41 | public @interface PatternType { 42 | int SQUARES = 0; 43 | int VERTICAL_LINES = 1; 44 | int HORIZONTAL_LINES = 2; 45 | int SCALES = 3; 46 | int RANDOM_TRIANGLES = 4; 47 | } 48 | 49 | // Constants for mText alignment in drawText() 50 | @Retention(RetentionPolicy.SOURCE) 51 | @IntDef({ 52 | TextAlign.UPPER_LEFT, 53 | TextAlign.LOWER_LEFT, 54 | TextAlign.CENTER, 55 | TextAlign.UPPER_RIGHT, 56 | TextAlign.LOWER_RIGHT 57 | }) 58 | public @interface TextAlign { 59 | int UPPER_LEFT = 0; 60 | int LOWER_LEFT = 1; 61 | int CENTER = 2; 62 | int UPPER_RIGHT = 3; 63 | int LOWER_RIGHT = 4; 64 | } 65 | 66 | /** 67 | * Generate a square-tiled Bitmap. 68 | * 69 | * @param width the desired mWidth for the bitmap 70 | * @param height the desired mHeight for the bitmap 71 | * @param tilesOnSmallerSide the number of tiles on the smaller side 72 | * @param palette the mPalette used for color randomization, nullable 73 | * @param colorType the type of color returned for color randomization, 74 | * RandomColor.ColorType.GRAY by default 75 | * @param seed the mSeed applied to the Random object passed during generation 76 | * @return a bitmap with squares generated according to given parameters 77 | */ 78 | private static Bitmap generateSquares(@IntRange(from = 1) final int width, 79 | @IntRange(from = 1) final int height, 80 | @IntRange(from = 1) final int tilesOnSmallerSide, 81 | @Nullable final int[] palette, 82 | @RandomColor.ColorType final int colorType, 83 | long seed) { 84 | 85 | final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 86 | final Canvas canvas = new Canvas(bitmap); 87 | final Paint paint = new Paint(); 88 | 89 | final Random random = getRandomForSeed(seed); 90 | int smallerSide = Math.min(width, height); 91 | final float SQUARE_SIZE = (float) smallerSide / tilesOnSmallerSide; 92 | 93 | for (int i = 0, j = 0; j < (height / SQUARE_SIZE); i++) { 94 | 95 | paint.setColor(RandomColor.get(palette, colorType, random)); 96 | 97 | canvas.drawRect(i * SQUARE_SIZE, j * SQUARE_SIZE, 98 | (i + 1) * SQUARE_SIZE, (j + 1) * SQUARE_SIZE, paint); 99 | 100 | if (i != 0 && i == (width / SQUARE_SIZE) - 1) { 101 | i = -1; 102 | j++; 103 | } 104 | } 105 | 106 | return bitmap; 107 | } 108 | 109 | /** 110 | * Generate a Bitmap of n horizontal lines. 111 | * 112 | * @param width the desired mWidth for the bitmap 113 | * @param height the desired mHeight for the bitmap 114 | * @param numberOfLines the number of horizontal lines 115 | * @param palette the mPalette used for color randomization, nullable 116 | * @param colorType the type of color returned for color randomization, 117 | * RandomColor.ColorType.GRAY by default 118 | * @param seed the mSeed applied to the Random object passed during generation 119 | * @return a bitmap with horizontal lines generated according to given parameters 120 | */ 121 | private static Bitmap generateHorizontalLines(@IntRange(from = 1) final int width, 122 | @IntRange(from = 1) final int height, 123 | @IntRange(from = 1) final int numberOfLines, 124 | @Nullable final int[] palette, 125 | @RandomColor.ColorType final int colorType, 126 | long seed) { 127 | 128 | final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 129 | final Canvas canvas = new Canvas(bitmap); 130 | final Paint paint = new Paint(); 131 | Random random = getRandomForSeed(seed); 132 | 133 | final float LINE_SIZE = (float) height / numberOfLines; 134 | 135 | for (int i = 0; i < numberOfLines; i++) { 136 | paint.setColor(RandomColor.get(palette, colorType, random)); 137 | canvas.drawRect(0, i * LINE_SIZE, width, (i + 1) * LINE_SIZE, paint); 138 | } 139 | 140 | return bitmap; 141 | } 142 | 143 | /** 144 | * Generate a Bitmap of n vertical lines. 145 | * 146 | * @param width the desired mWidth for the bitmap 147 | * @param height the desired mHeight for the bitmap 148 | * @param numberOfLines the number of vertical lines 149 | * @param palette the mPalette used for color randomization, nullable 150 | * @param colorType the type of color returned for color randomization, 151 | * RandomColor.ColorType.GRAY by default 152 | * @param seed the mSeed applied to the Random object passed during generation 153 | * @return a bitmap with vertical lines generated according to given parameters 154 | */ 155 | private static Bitmap generateVerticalLines(@IntRange(from = 1) final int width, 156 | @IntRange(from = 1) final int height, 157 | @IntRange(from = 1) final int numberOfLines, 158 | @Nullable final int[] palette, 159 | @RandomColor.ColorType final int colorType, 160 | long seed) { 161 | 162 | final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 163 | final Canvas canvas = new Canvas(bitmap); 164 | final Paint paint = new Paint(); 165 | Random random = getRandomForSeed(seed); 166 | 167 | final float LINE_SIZE = (float) width / numberOfLines; 168 | 169 | for (int i = 0; i < numberOfLines; i++) { 170 | paint.setColor(RandomColor.get(palette, colorType, random)); 171 | canvas.drawRect(i * LINE_SIZE, 0, (i + 1) * LINE_SIZE, height, paint); 172 | } 173 | 174 | return bitmap; 175 | } 176 | 177 | /** 178 | * Generate a Bitmap with staggered rows of fish-like scales. 179 | * 180 | * @param width the desired mWidth for the bitmap 181 | * @param height the desired mHeight for the bitmap 182 | * @param scalesPerRow the number of scales per row 183 | * @param palette the mPalette used for color randomization, nullable 184 | * @param colorType the type of color returned for color randomization, 185 | * RandomColor.ColorType.GRAY by default 186 | * @param seed the mSeed applied to the Random object passed during generation 187 | * @return a bitmap with staggered rows of scales generated according to given parameters 188 | */ 189 | private static Bitmap generateFishScales(@IntRange(from = 1) final int width, 190 | @IntRange(from = 1) final int height, 191 | @IntRange(from = 1) final int scalesPerRow, 192 | @Nullable final int[] palette, 193 | @RandomColor.ColorType final int colorType, 194 | long seed) { 195 | final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 196 | final Canvas canvas = new Canvas(bitmap); 197 | final Paint paint = new Paint(); 198 | paint.setFlags(Paint.ANTI_ALIAS_FLAG); 199 | Random random = getRandomForSeed(seed); 200 | 201 | final float SCALE_SIZE = (float) width / scalesPerRow; 202 | final float RADIUS = SCALE_SIZE / 2; 203 | 204 | for (int i = 0, j = 0; j < (height / RADIUS) + 1; i += 2) { 205 | paint.setColor(RandomColor.get(palette, colorType, random)); 206 | 207 | if (j % 2 == 0) { 208 | canvas.drawCircle((i + 1) * RADIUS, j * RADIUS, RADIUS, paint); 209 | } else { 210 | canvas.drawCircle(i * RADIUS, j * RADIUS, RADIUS, paint); 211 | } 212 | 213 | if (i * RADIUS > width) { 214 | i = -2; 215 | j++; 216 | } 217 | } 218 | 219 | return bitmap; 220 | } 221 | 222 | /** 223 | * Generate a Bitmap with random triangle strips 224 | * 225 | * @param width the desired mWidth for the bitmap 226 | * @param height the desired mHeight for the bitmap 227 | * @param rows the number of rows 228 | * @param palette the mPalette used for color randomization, nullable 229 | * @param colorType the type of color returned for color randomization, 230 | * RandomColor.ColorType.GRAY by default 231 | * @param seed the mSeed applied to the Random object passed during generation 232 | * @return a bitmap with randomly generated triangles according to given parameters 233 | */ 234 | private static Bitmap generateRandomTriangles(@IntRange(from = 1) final int width, 235 | @IntRange(from = 1) final int height, 236 | @IntRange(from = 1) final int rows, 237 | @Nullable @Size(min = 1) final int[] palette, 238 | @RandomColor.ColorType final int colorType, 239 | long seed) { 240 | 241 | final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 242 | final Canvas canvas = new Canvas(bitmap); 243 | final Paint paint = new Paint(); 244 | paint.setFlags(Paint.ANTI_ALIAS_FLAG); 245 | paint.setStyle(Paint.Style.FILL_AND_STROKE); 246 | paint.setStrokeWidth(1); 247 | Path path = new Path(); 248 | Random random = getRandomForSeed(seed); 249 | 250 | final Point[] VERTICES = getVerticesForRandomTriangles(width, height, rows, random); 251 | final float STEP = (float) height / rows; 252 | final int COLUMNS = (int) (width / STEP); 253 | 254 | for (int i = 0, j = 0; j < rows; i++) { 255 | 256 | int a = i + j * (COLUMNS + 1); 257 | int b = a + 1; 258 | int c = a + (COLUMNS + 1); 259 | int d = c + 1; 260 | 261 | Point pa = VERTICES[a]; 262 | Point pb = VERTICES[b]; 263 | Point pc = VERTICES[c]; 264 | Point pd = VERTICES[d]; 265 | 266 | setPathForPoints(path, pa, pb, pc, pa); 267 | paint.setColor(RandomColor.get(palette, colorType, random)); 268 | canvas.drawPath(path, paint); 269 | 270 | setPathForPoints(path, pb, pc, pd, pb); 271 | paint.setColor(RandomColor.get(palette, colorType, random)); 272 | canvas.drawPath(path, paint); 273 | 274 | if (i == COLUMNS - 1) { 275 | i = -1; 276 | j++; 277 | } 278 | } 279 | 280 | return bitmap; 281 | } 282 | 283 | /** 284 | * Set given path to represent a shape with given points. 285 | * 286 | * @param path the path to setup 287 | * @param points variadic Point objects for shape generation 288 | */ 289 | private static void setPathForPoints(@NonNull Path path, @Size(min = 3) Point... points) { 290 | path.reset(); 291 | 292 | path.moveTo(points[0].getX(), points[0].getY()); 293 | 294 | for (Point point : points) { 295 | path.lineTo(point.getX(), point.getY()); 296 | } 297 | 298 | path.close(); 299 | } 300 | 301 | /** 302 | * Generate vertices for RANDOM_TRIANGLES generation. 303 | *

304 | * Except for corners, every coordinate is generated with a random margin on one or both axes. 305 | * 306 | * @param width the desired mWidth for the bitmap 307 | * @param height the desired mHeight for the bitmap 308 | * @param rows the number of horizontal triangle strips 309 | * @param random the random instance passed from generateRandomTriangles() 310 | * @return an array of coordinates used in generateRandomTriangles() 311 | */ 312 | @SuppressLint("NewApi") 313 | private static Point[] getVerticesForRandomTriangles(@IntRange(from = 1) final int width, 314 | @IntRange(from = 1) final int height, 315 | @IntRange(from = 1) final int rows, 316 | @NonNull Random random) { 317 | 318 | final float STEP = (float) height / rows; 319 | final int COLUMNS = (int) (width / STEP); 320 | final float MARGIN = STEP * .75f; 321 | final float HALF_MARGIN = MARGIN / 2; 322 | 323 | int arraySize = (rows + 1) * (COLUMNS + 1); 324 | Point[] vertices = new Point[arraySize]; 325 | int n = 0; 326 | 327 | // First line 328 | vertices[n++] = new Point(0.f, 0.f); 329 | 330 | for (int i = 1; i < COLUMNS; i++) { 331 | vertices[n++] = new Point((i * STEP) - HALF_MARGIN + (random.nextFloat() * MARGIN), 0.f); 332 | } 333 | 334 | vertices[n++] = new Point(width, 0.f); 335 | 336 | // N-lines 337 | for (int i = 0, j = 1; j < rows; i++) { 338 | if (i == 0) { 339 | vertices[n++] = new Point(0.f, (j * STEP) - HALF_MARGIN + (random.nextFloat() * MARGIN)); 340 | } else if (i == COLUMNS) { 341 | vertices[n++] = new Point(width, (j * STEP) - HALF_MARGIN + (random.nextFloat() * MARGIN)); 342 | 343 | i = -1; 344 | j++; 345 | } else { 346 | vertices[n++] = new Point((i * STEP) - HALF_MARGIN + (random.nextFloat() * MARGIN), 347 | (j * STEP) - HALF_MARGIN + (random.nextFloat() * MARGIN)); 348 | } 349 | } 350 | 351 | // Last line 352 | vertices[n++] = new Point(0.f, height); 353 | 354 | for (int i = 1; i < COLUMNS; i++) { 355 | vertices[n++] = new Point((i * STEP) - HALF_MARGIN + (random.nextFloat() * MARGIN), height); 356 | } 357 | 358 | vertices[n] = new Point(width, height); 359 | 360 | return vertices; 361 | } 362 | 363 | /** 364 | * Draw mText on given Bitmap. 365 | *

366 | * Margin constant is set at 2.6% of the bitmap smallest side. (4dp for 150dp side) 367 | * Text size will be set accordingly to the bitmap mWidth minus left and right margins. 368 | * 369 | * @param bitmap the generated bitmap to draw on 370 | * @param text the mText to be drawn on given bitmap 371 | * @param textColor the mText color 372 | * @param textAlign the mText alignment 373 | * @return a bitmap previously generated by the builder with given mText on it 374 | */ 375 | public static Bitmap drawText(@NonNull Bitmap bitmap, String text, 376 | @ColorInt final int textColor, @TextAlign final int textAlign) { 377 | if (text.trim().equals("")) { 378 | return bitmap; 379 | } 380 | 381 | Canvas canvas = new Canvas(bitmap); 382 | Paint paint = new Paint(); 383 | paint.setAntiAlias(true); 384 | paint.setColor(textColor); 385 | paint.setTypeface(Typeface.create(paint.getTypeface(), Typeface.BOLD)); 386 | 387 | final int WIDTH = bitmap.getWidth(); 388 | final int HEIGHT = bitmap.getHeight(); 389 | final int SMALLER_SIDE = Math.min(WIDTH, HEIGHT); 390 | final float MARGIN = SMALLER_SIDE / 37.5f; 391 | 392 | if (text.length() < 3) { 393 | paint.setTextSize(SMALLER_SIDE / 2); 394 | } else { 395 | paint.setTextSize(SMALLER_SIDE / 3); 396 | } 397 | 398 | float textWidth = paint.measureText(text); 399 | if (textWidth + (MARGIN * 2) > WIDTH) { 400 | paint.setTextSize(paint.getTextSize() * ((WIDTH - MARGIN) / textWidth)); 401 | } 402 | 403 | paint.setColor(textColor); 404 | 405 | // Setting x, y coordinates for TextAlign.CENTER as default 406 | final Rect textBounds = new Rect(); 407 | paint.getTextBounds(text, 0, text.length(), textBounds); 408 | float x = WIDTH / 2 - textBounds.exactCenterX(); 409 | float y = HEIGHT / 2 - textBounds.exactCenterY(); 410 | 411 | switch (textAlign) { 412 | case TextAlign.UPPER_LEFT: 413 | paint.setTextAlign(Paint.Align.LEFT); 414 | x = MARGIN; 415 | y = textBounds.height() + MARGIN; 416 | break; 417 | case TextAlign.LOWER_LEFT: 418 | paint.setTextAlign(Paint.Align.LEFT); 419 | x = MARGIN; 420 | y = HEIGHT - MARGIN; 421 | break; 422 | case TextAlign.CENTER: 423 | paint.setTextAlign(Paint.Align.LEFT); 424 | break; 425 | case TextAlign.UPPER_RIGHT: 426 | paint.setTextAlign(Paint.Align.RIGHT); 427 | x = WIDTH - MARGIN; 428 | y = textBounds.height() + MARGIN; 429 | break; 430 | case TextAlign.LOWER_RIGHT: 431 | paint.setTextAlign(Paint.Align.RIGHT); 432 | x = WIDTH - MARGIN; 433 | y = HEIGHT - MARGIN; 434 | break; 435 | } 436 | canvas.drawText(text, x, y, paint); 437 | 438 | return bitmap; 439 | } 440 | 441 | /** 442 | * Return a seeded Random instance or a null one according to given mSeed. 443 | * 444 | * @param seed the mSeed for random generation 445 | * method will return a null Random object if mSeed equals zero 446 | * @return a seeded random or a null one 447 | */ 448 | private static Random getRandomForSeed(long seed) { 449 | return new Random(seed); 450 | } 451 | 452 | private static class Point { 453 | 454 | private final float x; 455 | private final float y; 456 | 457 | Point(float x, float y) { 458 | this.x = x; 459 | this.y = y; 460 | } 461 | 462 | float getX() { 463 | return x; 464 | } 465 | 466 | float getY() { 467 | return y; 468 | } 469 | 470 | } 471 | 472 | /** 473 | * A bitmap builder with various tiling patterns. Using generate() without any parameter set will 474 | * return a 150 by 150 textless gray bitmap with 3 by 3 square tiling. 475 | *

476 | * Example : 477 | *

478 |      *     {@code
479 |      * bitmap = new PatternPlaceholder.Builder()
480 |      *     .setSize(MyContainer.mWidth())
481 |      *     .setTilesPerSide(4)
482 |      *     .setPatternType(PatternPlaceholder.PatternType.RANDOM_TRIANGLES)
483 |      *     .setColorGenerationType(RandomColor.ColorType.DARK_GRAY)
484 |      *     .setText("SCALES")
485 |      *     .setTextColor(Color.WHITE)
486 |      *     .generate();
487 |      *     }
488 |      * 
489 | */ 490 | public static class Builder { 491 | 492 | private int mWidth = 150; 493 | private int mHeight = 150; 494 | private int mTilesPerSide = 3; 495 | private int[] mPalette; 496 | private int mColorGenerationType = RandomColor.ColorType.GREY; 497 | private int mPatternType = PatternType.SQUARES; 498 | private String mText; 499 | private int mTextColor = Color.BLACK; 500 | private int mTextAlign = TextAlign.CENTER; 501 | private long mSeed = new Random().nextLong(); 502 | private boolean mIsCachingEnabled = false; 503 | 504 | private final Context mContext; 505 | 506 | public Builder(Context context) { 507 | mContext = context; 508 | } 509 | 510 | public PatternPlaceholder.Builder setSize(@IntRange(from = 1) int width, 511 | @IntRange(from = 1) int height) { 512 | mWidth = width; 513 | mHeight = height; 514 | return this; 515 | } 516 | 517 | public PatternPlaceholder.Builder setTilesPerSide(@IntRange(from = 1) int tilesPerSide) { 518 | mTilesPerSide = tilesPerSide; 519 | return this; 520 | } 521 | 522 | public PatternPlaceholder.Builder setPalette(@Nullable @Size(min = 1) int[] palette) { 523 | mPalette = palette; 524 | return this; 525 | } 526 | 527 | public PatternPlaceholder.Builder setColorGenerationType(@RandomColor.ColorType int colorGenerationType) { 528 | mColorGenerationType = colorGenerationType; 529 | return this; 530 | } 531 | 532 | public PatternPlaceholder.Builder setPatternType(@PatternType int patternType) { 533 | mPatternType = patternType; 534 | return this; 535 | } 536 | 537 | public PatternPlaceholder.Builder setSeed(long seed) { 538 | mSeed = seed; 539 | return this; 540 | } 541 | 542 | public PatternPlaceholder.Builder setText(@Nullable String text) { 543 | mText = text; 544 | return this; 545 | } 546 | 547 | public PatternPlaceholder.Builder setTextColor(@ColorInt int textColor) { 548 | mTextColor = textColor; 549 | return this; 550 | } 551 | 552 | public PatternPlaceholder.Builder setTextAlign(@TextAlign int textAlign) { 553 | mTextAlign = textAlign; 554 | return this; 555 | } 556 | 557 | public PatternPlaceholder.Builder withCacheEnabled(boolean isCachingEnabled) { 558 | mIsCachingEnabled = isCachingEnabled; 559 | return this; 560 | } 561 | 562 | /** 563 | * Generate and return the bitmap synchronously. 564 | */ 565 | public Bitmap generate() { 566 | long start = System.currentTimeMillis(); 567 | Bitmap bitmap; 568 | 569 | BitmapFetcher fetcher = null; 570 | if (mIsCachingEnabled) { 571 | fetcher = new BitmapFetcher(mContext); 572 | 573 | bitmap = fetcher.getBitmapFromCache(hashCode() + ""); 574 | if (bitmap != null) { 575 | Log.i("Fetcher", "Read bitmap from cache"); 576 | // Log.i("BUILDER-TIME", "" + (System.currentTimeMillis() - start)); 577 | return bitmap; 578 | } 579 | } 580 | 581 | switch (mPatternType) { 582 | case PatternType.SQUARES: 583 | bitmap = generateSquares(mWidth, mHeight, mTilesPerSide, 584 | mPalette, mColorGenerationType, mSeed); 585 | break; 586 | case PatternType.VERTICAL_LINES: 587 | bitmap = generateVerticalLines(mWidth, mHeight, mTilesPerSide, 588 | mPalette, mColorGenerationType, mSeed); 589 | break; 590 | case PatternType.HORIZONTAL_LINES: 591 | bitmap = generateHorizontalLines(mWidth, mHeight, mTilesPerSide, 592 | mPalette, mColorGenerationType, mSeed); 593 | break; 594 | case PatternType.SCALES: 595 | bitmap = generateFishScales(mWidth, mHeight, mTilesPerSide, 596 | mPalette, mColorGenerationType, mSeed); 597 | break; 598 | case PatternType.RANDOM_TRIANGLES: 599 | bitmap = generateRandomTriangles(mWidth, mHeight, mTilesPerSide, 600 | mPalette, mColorGenerationType, mSeed); 601 | break; 602 | default: 603 | bitmap = generateSquares(mWidth, mHeight, mTilesPerSide, 604 | mPalette, mColorGenerationType, mSeed); 605 | break; 606 | } 607 | 608 | if (mText != null) { 609 | bitmap = drawText(bitmap, mText, mTextColor, mTextAlign); 610 | } 611 | 612 | if (mIsCachingEnabled) { 613 | if (fetcher != null) { 614 | fetcher.addBitmapToCache(hashCode() + "", bitmap); 615 | Log.i("Fetcher", "Wrote bitmap on cache"); 616 | } 617 | } 618 | 619 | // Log.i("BUILDER-TIME", "" + (System.currentTimeMillis() - start)); 620 | 621 | return bitmap; 622 | } 623 | 624 | /** 625 | * Generate the bitmap asynchronously. 626 | *

627 | * onGenerated(Bitmap) will be called by the listener on completion. 628 | */ 629 | public AsyncTask generate(PatternGeneratorAsyncListener listener) { 630 | return new PatternPlaceholderAsyncTask(listener).execute(this); 631 | } 632 | 633 | /** 634 | * Generate the bitmap asynchronously and load it into provided ImageView. 635 | */ 636 | public AsyncTask generate(ImageView imageView) { 637 | // In case of lengthy generation, preset imageview's background with a color from 638 | // desired mPalette or generation type 639 | imageView.setBackgroundColor(RandomColor.get(mPalette, mColorGenerationType, new Random())); 640 | return new PatternPlaceholderAsyncTask(imageView).execute(this); 641 | } 642 | 643 | @Override 644 | public boolean equals(Object o) { 645 | if (this == o) return true; 646 | if (o == null || getClass() != o.getClass()) return false; 647 | 648 | Builder builder = (Builder) o; 649 | 650 | if (mWidth != builder.mWidth) return false; 651 | if (mHeight != builder.mHeight) return false; 652 | if (mTilesPerSide != builder.mTilesPerSide) return false; 653 | if (mColorGenerationType != builder.mColorGenerationType) return false; 654 | if (mPatternType != builder.mPatternType) return false; 655 | if (mTextColor != builder.mTextColor) return false; 656 | if (mTextAlign != builder.mTextAlign) return false; 657 | if (mSeed != builder.mSeed) return false; 658 | if (!Arrays.equals(mPalette, builder.mPalette)) return false; 659 | 660 | return mText != null ? mText.equals(builder.mText) : builder.mText == null; 661 | } 662 | 663 | @Override 664 | public int hashCode() { 665 | int result = mWidth; 666 | result = 31 * result + mHeight; 667 | result = 31 * result + mTilesPerSide; 668 | result = 31 * result + (mPalette != null ? Arrays.hashCode(mPalette) : 0); 669 | result = 31 * result + mColorGenerationType; 670 | result = 31 * result + mPatternType; 671 | result = 31 * result + (mText != null ? mText.hashCode() : 0); 672 | result = 31 * result + mTextColor; 673 | result = 31 * result + mTextAlign; 674 | result = 31 * result + (int) (mSeed ^ (mSeed >>> 32)); 675 | return result; 676 | } 677 | } 678 | 679 | 680 | public interface PatternGeneratorAsyncListener { 681 | 682 | void onGenerated(Bitmap bitmap); 683 | 684 | } 685 | } 686 | -------------------------------------------------------------------------------- /patternplaceholder/src/main/java/be/omnuzel/patternplaceholder/PatternPlaceholderAsyncTask.java: -------------------------------------------------------------------------------- 1 | package be.omnuzel.patternplaceholder; 2 | 3 | import android.graphics.Bitmap; 4 | import android.os.AsyncTask; 5 | import android.support.annotation.NonNull; 6 | import android.widget.ImageView; 7 | 8 | /** 9 | * Created by De Cooman Sammy on 18/11/16. 10 | */ 11 | 12 | public class PatternPlaceholderAsyncTask extends AsyncTask { 13 | 14 | private PatternPlaceholder.PatternGeneratorAsyncListener mCallback; 15 | private ImageView mImageView; 16 | 17 | public PatternPlaceholderAsyncTask(@NonNull PatternPlaceholder.PatternGeneratorAsyncListener callback) { 18 | this.mCallback = callback; 19 | } 20 | 21 | public PatternPlaceholderAsyncTask(@NonNull ImageView imageView) { 22 | this.mImageView = imageView; 23 | } 24 | 25 | @Override 26 | protected Bitmap doInBackground(PatternPlaceholder.Builder... builders) { 27 | return builders[0].generate(); 28 | } 29 | 30 | @Override 31 | protected void onPostExecute(Bitmap bitmap) { 32 | super.onPostExecute(bitmap); 33 | 34 | if (mImageView != null) { 35 | mImageView.setImageBitmap(bitmap); 36 | } else { 37 | mCallback.onGenerated(bitmap); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /patternplaceholder/src/main/java/be/omnuzel/patternplaceholder/RandomColor.java: -------------------------------------------------------------------------------- 1 | package be.omnuzel.patternplaceholder; 2 | 3 | import android.graphics.Color; 4 | import android.support.annotation.IntDef; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.RetentionPolicy; 10 | import java.util.Random; 11 | 12 | /** 13 | * Created by De Cooman Sammy on 11/11/16. 14 | */ 15 | 16 | public final class RandomColor { 17 | 18 | @Retention(RetentionPolicy.SOURCE) 19 | @IntDef({ 20 | ColorType.ALL, 21 | ColorType.LIGHT_GREY, 22 | ColorType.MEDIUM_GREY, 23 | ColorType.DARK_GREY, 24 | ColorType.GREY}) 25 | public @interface ColorType { 26 | int ALL = 0; 27 | int LIGHT_GREY = 1; 28 | int MEDIUM_GREY = 2; 29 | int DARK_GREY = 3; 30 | int GREY = 4; 31 | } 32 | 33 | /** 34 | * Return a random color from provided palette or a random color generated for a given ColorType. 35 | *

36 | * Color type default is ColorType.GREY 37 | * 38 | * @param palette an integer array with color codes 39 | * @param colorType the type of color returned for color randomization, ColorType.GREY by default 40 | * @param random the Random instance passed from PatternPlaceholder, non null 41 | * @return a randomly chosen color from given palette or a randomly generated color if palette is null 42 | */ 43 | public static int get(@Nullable int[] palette, @ColorType int colorType, @NonNull Random random) { 44 | if (palette != null) { 45 | return palette[(int) (random.nextFloat() * palette.length)]; 46 | } else { 47 | switch (colorType) { 48 | case ColorType.ALL: 49 | return getColor(random); 50 | case ColorType.LIGHT_GREY: 51 | return getLightGrey(random); 52 | case ColorType.MEDIUM_GREY: 53 | return getMediumGrey(random); 54 | case ColorType.DARK_GREY: 55 | return getRandomDarkGrey(random); 56 | case ColorType.GREY: 57 | return getGrey(random); 58 | default: 59 | return getGrey(random); 60 | } 61 | } 62 | } 63 | 64 | /** 65 | * Generate a random color 66 | * 67 | * @param random the Random instance passed from PatternPlaceholder, non null 68 | * @return the randomly generated color 69 | */ 70 | public static int getColor(@NonNull Random random) { 71 | 72 | int red = random.nextInt(255); 73 | int green = random.nextInt(255); 74 | int blue = random.nextInt(255); 75 | return Color.rgb(red, green, blue); 76 | } 77 | 78 | /** 79 | * Generate a random grey of range 0-255 80 | * 81 | * @param random the Random instance passed from PatternPlaceholder, non null 82 | * @return the randomly generated grey 83 | */ 84 | public static int getGrey(@NonNull Random random) { 85 | 86 | int value = random.nextInt(256); 87 | return Color.rgb(value, value, value); 88 | } 89 | 90 | /** 91 | * Generate a random grey of range 155-255 92 | * 93 | * @param random the Random instance passed from PatternPlaceholder, non null 94 | * @return the randomly generated grey 95 | */ 96 | public static int getLightGrey(@NonNull Random random) { 97 | 98 | int value = random.nextInt(101) + 155; 99 | return Color.rgb(value, value, value); 100 | } 101 | 102 | /** 103 | * Generate a random grey of range 100-200 104 | * 105 | * @param random the Random instance passed from PatternPlaceholder, non null 106 | * @return the randomly generated grey 107 | */ 108 | public static int getMediumGrey(@NonNull Random random) { 109 | 110 | int value = random.nextInt(101) + 100; 111 | return Color.rgb(value, value, value); 112 | } 113 | 114 | /** 115 | * Generate a random grey of range 0-100 116 | * 117 | * @param random the Random instance passed from PatternPlaceholder, non null 118 | * @return the randomly generated grey 119 | */ 120 | public static int getRandomDarkGrey(@NonNull Random random) { 121 | 122 | int value = random.nextInt(101); 123 | return Color.rgb(value, value, value); 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /patternplaceholder/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | PatternPlaceholder 3 | 4 | -------------------------------------------------------------------------------- /patternplaceholder/src/test/java/be/omnuzel/patternplaceholder/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package be.omnuzel.patternplaceholder; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':patternplaceholder' 2 | --------------------------------------------------------------------------------