Wednesday, September 30, 2015

Android Studio AVD Manager now support Nexus 6P/5X profile

Android Studio AVD Manager now support Nexus 6P/5X profile, you can create AVD (Android Virtual Device) running Android 6, Marshmallow, API 23.






Create AVD of Nexus 6P running Android 6 Marshmallow

FREE ebook - Java Application Development on Linux

“Java™ Application Development on Linux®”

is the hands-on guide to the full Java application development lifecycle on Linux.

Linux is the fastest-growing Java development platform because it saves money and time by serving as a platform for both development and deployment. But developers face significant platform-specific challenges and opportunities when managing and deploying Java applicaitons in a controlled production environment.

After a simple command-line application introduces basic tools this program leads readers through business-logic object analysis, database design, Java servlet UIs, Java ServerPages (JSP) UISs, Swing GUIs, and Standard Widget Toolkit (SWT) GUIs. Scaling up to the enterprise level provides the opportunity to use both the JBoss Application Server and the Apache Geronimo Application Server, and Enterprise JavaBeans (EJB).

download link: http://javalinuxbook.com/

Android Studio 1.4 is available in the stable channel




Tuesday, September 29, 2015

Know the news from Google Android


Google just announced:
  • New Nexus phone running Marshmallow: Nexus 6P and 5X
  • The first Android tablet built by Google, Pixel C, and the Chromebook Pixel
  • The new Chromecast and Chromecast Audio
  • Google Play Music and Google Photos

Google Press Event 9/29/15

Check Official Google Blog

AndroidMarshmallow will begin rolling out to Nexus 5, 6, 7, 9 and Nexus Player starting next week

Android official Google+ announced that "#AndroidMarshmallow will begin rolling out to Nexus 5, 6, 7, 9 and Nexus Player starting next week".


check the original post.

Extract Prominent Colors from an Image, using Palette class



The Android Support Library r21 and above includes the Palette class, which lets you extract prominent colors from an image. This class extracts the following prominent colors:
- Vibrant
- Vibrant dark
- Vibrant light
- Muted
- Muted dark
- Muted light

reference: http://developer.android.com/training/material/drawables.html#ColorExtract

This example show how to load photos, and get Prominent Colors using Palette class.
(Actually I don't know what the Prominent Colors means!)

To use the Palette class in your project, add the following Gradle dependency to your app's module:
dependencies {
    ...
    compile 'com.android.support:palette-v7:xx.x.x'
}


com.blogspot.android_er.androidpalette.MainActivity.java
package com.blogspot.android_er.androidpalette;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.graphics.Palette;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import java.io.FileNotFoundException;

public class MainActivity extends AppCompatActivity {

    Button buttonOpen;
    TextView textUri;
    ImageView imageView;
    TextView textVibrant, textVibrantDark, textVibrantLight;
    TextView textMuted, textMutedDark, textMutedLight;
    View viewVibrant, viewVibrantDark, viewVibrantLight;
    View viewMuted, viewMutedDark, viewMutedLight;

    private static final int RQS_OPEN_IMAGE = 1;

    Uri targetUri = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textUri = (TextView) findViewById(R.id.texturi);
        imageView = (ImageView) findViewById(R.id.image);
        buttonOpen = (Button) findViewById(R.id.btnopen);
        buttonOpen.setOnClickListener(buttonOpenOnClickListener);

        textVibrant = (TextView)findViewById(R.id.textVibrant);
        textVibrantDark = (TextView)findViewById(R.id.textVibrantDark);
        textVibrantLight = (TextView)findViewById(R.id.textVibrantLight);
        textMuted = (TextView)findViewById(R.id.textMuted);
        textMutedDark = (TextView)findViewById(R.id.textMutedDark);
        textMutedLight = (TextView)findViewById(R.id.textMutedLight);

        viewVibrant = (View)findViewById(R.id.viewVibrant);
        viewVibrantDark = (View)findViewById(R.id.viewVibrantDark);
        viewVibrantLight = (View)findViewById(R.id.viewVibrantLight);
        viewMuted = (View)findViewById(R.id.viewMuted);
        viewMutedDark = (View)findViewById(R.id.viewMutedDark);
        viewMutedLight = (View)findViewById(R.id.viewMutedLight);
    }

    View.OnClickListener buttonOpenOnClickListener =
            new View.OnClickListener() {

                @TargetApi(Build.VERSION_CODES.KITKAT)
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent();

                    if (Build.VERSION.SDK_INT >=
                            Build.VERSION_CODES.KITKAT) {
                        intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
                    } else {
                        intent.setAction(Intent.ACTION_GET_CONTENT);
                    }

                    intent.addCategory(Intent.CATEGORY_OPENABLE);

                    // set MIME type for image
                    intent.setType("image/*");

                    startActivityForResult(intent, RQS_OPEN_IMAGE);
                }

            };

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @Override
    protected void onActivityResult(int requestCode,
                                    int resultCode, Intent data) {

        if (resultCode == Activity.RESULT_OK) {

            Uri dataUri = data.getData();

            if (requestCode == RQS_OPEN_IMAGE) {
                targetUri = dataUri;
                textUri.setText(dataUri.toString());
                updatImage(dataUri);
            }
        }

    }

    private void updatImage(Uri uri){

        if (uri != null){
            Bitmap bm;
            try {
                bm = BitmapFactory.decodeStream(
                        getContentResolver()
                                .openInputStream(uri));
                imageView.setImageBitmap(bm);

                extractProminentColors(bm);

            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    //extract prominent colors
    /*
    compile 'com.android.support:palette-v7:23.0.1'
    is needed in Gradle dependency
     */
    private void extractProminentColors(Bitmap bitmap){
        int defaultColor = 0x000000;

        Palette p = Palette.from(bitmap).generate();

        int VibrantColor = p.getVibrantColor(defaultColor);
        textVibrant.setText("VibrantColor: " + String.format("#%X", VibrantColor));
        viewVibrant.setBackgroundColor(VibrantColor);

        int VibrantColorDark = p.getDarkVibrantColor(defaultColor);
        textVibrantDark.setText("VibrantColorDark: " + String.format("#%X", VibrantColorDark));
        viewVibrantDark.setBackgroundColor(VibrantColorDark);

        int VibrantColorLight = p.getLightVibrantColor(defaultColor);
        textVibrantLight.setText("VibrantColorLight: " + String.format("#%X", VibrantColorLight));
        viewVibrantLight.setBackgroundColor(VibrantColorLight);

        int MutedColor = p.getMutedColor(defaultColor);
        textMuted.setText("MutedColor: " + String.format("#%X", MutedColor));
        viewMuted.setBackgroundColor(MutedColor);

        int MutedColorDark = p.getDarkMutedColor(defaultColor);
        textMutedDark.setText("MutedColorDark: " + String.format("#%X", MutedColorDark));
        viewMutedDark.setBackgroundColor(MutedColorDark);

        int MutedColorLight = p.getLightMutedColor(defaultColor);
        textMutedLight.setText("MutedColorLight: " + String.format("#%X", MutedColorLight));
        viewMutedLight.setBackgroundColor(MutedColorLight);

    }

}


layout/activity_main.xml
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold"/>
    <Button
        android:id="@+id/btnopen"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Load image"/>
    
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView
                android:id="@+id/texturi"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
            <ImageView
                android:id="@+id/image"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:adjustViewBounds="true"/>

            <TextView
                android:id="@+id/textVibrant"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Vibrant"/>
            <View
                android:id="@+id/viewVibrant"
                android:layout_width="match_parent"
                android:layout_height="25dp"/>

            <TextView
                android:id="@+id/textVibrantDark"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="VibrantDark"/>
            <View
                android:id="@+id/viewVibrantDark"
                android:layout_width="match_parent"
                android:layout_height="25dp"/>

            <TextView
                android:id="@+id/textVibrantLight"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="VibrantLight"/>
            <View
                android:id="@+id/viewVibrantLight"
                android:layout_width="match_parent"
                android:layout_height="25dp"/>

            <TextView
                android:id="@+id/textMuted"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Muted"/>
            <View
                android:id="@+id/viewMuted"
                android:layout_width="match_parent"
                android:layout_height="25dp"/>

            <TextView
                android:id="@+id/textMutedDark"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="MutedDark"/>
            <View
                android:id="@+id/viewMutedDark"
                android:layout_width="match_parent"
                android:layout_height="25dp"/>

            <TextView
                android:id="@+id/textMutedLight"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="MutedLight"/>
            <View
                android:id="@+id/viewMutedLight"
                android:layout_width="match_parent"
                android:layout_height="25dp"/>

        </LinearLayout>
    </ScrollView>
</LinearLayout>



download filesDownload the APK to try .

Monday, September 28, 2015

Try android:elevation on TextView

Just try some effect of android:elevation on TextView, for various background.

layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="20dp"
    android:orientation="vertical"
    tools:context=".MainActivity"
    android:background="#ffffff">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:textSize="22dp"
        android:textStyle="bold"
        android:text="Simple TextView" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:textSize="22dp"
        android:textStyle="bold"
        android:text="TextView with elevation, no background"
        android:elevation="20dp" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:textSize="22dp"
        android:textStyle="bold"
        android:text="TextView with both elevation and background"
        android:background="#0000ff"
        android:elevation="20dp" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:textSize="22dp"
        android:textStyle="bold"
        android:text="TextView with both elevation and background (same as parent background)"
        android:background="#ffffff"
        android:elevation="20dp" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:textSize="22dp"
        android:textStyle="bold"
        android:textColor="#ffffff"
        android:text="TextView with both elevation and background (black)"
        android:background="#000000"
        android:elevation="20dp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:textSize="22dp"
        android:textStyle="bold"
        android:text="TextView with both elevation and transparent background"
        android:background="#00000000"
        android:elevation="20dp" />

</LinearLayout>


Test on Nexus 7, Android 5.1.1

If hardwareAccelerated is disabled in AndroidManifest.xml by adding android:hardwareAccelerated="false" in <application>, the shadow effect will disappear. (tested on Nexus 7 running Android 5.1.1)

src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.blogspot.android_er.androidelevation" >

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        android:hardwareAccelerated="false" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


android:hardwareAccelerated="false"

Friday, September 25, 2015

Divider and Space

Example to use divider and space
Create our divider in drawable folder:

drawable/myhdivider.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <size android:height="1dp" />
    <solid android:color="#A00000FF" />
</shape>

drawable/myvdivider.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <size android:width="1dp"/>
    <solid android:color="#A0FF0000" />
</shape>

Edit layout to use our dividers in LinearLayout, and also insert space.
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="20dp"
    android:orientation="vertical"
    android:divider="@drawable/myhdivider"
    android:showDividers="middle"
    tools:context=".MainActivity"
    android:background="#D0D0D0">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="android-er"
        android:textStyle="bold" />
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:divider="@drawable/myvdivider"
        android:dividerPadding="5dp"
        android:showDividers="middle"
        android:background="#B0B0B0">
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="button"/>
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="button"/>
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="button"/>
    </LinearLayout>
    <Space
        android:layout_width="match_parent"
        android:layout_height="50dp" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="button"
        android:background="?android:attr/selectableItemBackground"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="button"
        android:background="?android:attr/selectableItemBackground"/>


</LinearLayout>

Wednesday, September 23, 2015

Prevent CalledFromWrongThreadException


CalledFromWrongThreadException is a common error if you tried to send UI events to the UI thread from outside the UI thread.

In this example, there are 3 AsyncTask:

- MyAsyncTask1 update UI element in doInBackground() via publishProgress() & onProgressUpdate(), no error generated.

- MyAsyncTask1 update UI element in doInBackground() directly, error will reported:
Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

- MyAsyncTask1 update UI element in doInBackground() by calling runOnUiThread() with Runnable(),  no error generated.


MainActivity.java
package com.blogspot.android_er.androidcalledfromwrongthreadexception;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    TextView textView1, textView2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btn1 = (Button)findViewById(R.id.button1);
        Button btn2 = (Button)findViewById(R.id.button2);
        Button btn3 = (Button)findViewById(R.id.button3);
        textView1 = (TextView)findViewById(R.id.textview1);
        textView2 = (TextView)findViewById(R.id.textview2);

        btn1.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                new MyAsyncTask1().execute();
            }
        });

        btn2.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                new MyAsyncTask2().execute();
            }
        });

        btn3.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                new MyAsyncTask3().execute();
            }
        });
    }

    //No access UI in doInBackground()
    //No error
    private class MyAsyncTask1 extends AsyncTask<Void, Integer, Void>{

        int i;

        @Override
        protected void onPreExecute() {
            i = 0;
            textView1.setText("onPreExecute()");
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            textView1.setText("onPostExecute");
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            textView1.setText("onProgressUpdate(): " + values[0]);
        }

        @Override
        protected Void doInBackground(Void... params) {
            //update UI via publishProgress() & onProgressUpdate()
            while(i<10){
                publishProgress(i++);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    }

    //Update UI in background thread
    //error caused by CalledFromWrongThreadException!!!
    private class MyAsyncTask2 extends MyAsyncTask1{
        @Override
        protected Void doInBackground(Void... params) {

            while(i<10){
                //publishProgress(i++);
                textView2.setText("doInBackground(): " + String.valueOf(i++));
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    }

    //Update UI via runOnUiThread()
    //No error
    private class MyAsyncTask3 extends MyAsyncTask1{
        @Override
        protected Void doInBackground(Void... params) {

            while(i<10){
                //publishProgress(i++);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView2.setText("doInBackground(): " + String.valueOf(i++));
                    }
                });

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    }

}


layout/activity_main.xml
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="No access UI in doInBackground()"
        android:textAllCaps="false" />
    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Update UI in background thread\nCalledFromWrongThreadException"
        android:textAllCaps="false" />
    <Button
        android:id="@+id/button3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="runOnUiThread()"
        android:textAllCaps="false" />
    <TextView
        android:id="@+id/textview1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="40dp" />
    <TextView
        android:id="@+id/textview2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="40dp" />

</LinearLayout>

Example of using "?android:attr/selectableItemBackground" and "?android:attr/selectableItemBackgroundBorderless"


Example to apply "?android:attr/selectableItemBackground" and "?android:attr/selectableItemBackgroundBorderless" to android:background, in XML file.
  • ?android:attr/selectableItemBackground for a bounded ripple.
  • ?android:attr/selectableItemBackgroundBorderless for a ripple that extends beyond the view. It will be drawn upon, and bounded by, the nearest parent of the view with a non-null background. (introduced in API level 21)
reference: http://developer.android.com/training/material/animations.html#Touch


<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="30dp"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="30dp"
        android:orientation="vertical">
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Normal Button"/>
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="\?android:attr/selectableItemBackground"
            android:textAllCaps="false"
            android:background="?android:attr/selectableItemBackground" />
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="\?android:attr/selectableItemBackgroundBorderless"
            android:textAllCaps="false"
            android:background="?android:attr/selectableItemBackgroundBorderless" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="30dp"
        android:orientation="vertical"
        android:background="#80C0C0">
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Normal Button"/>
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="\?android:attr/selectableItemBackground"
            android:textAllCaps="false"
            android:background="?android:attr/selectableItemBackground" />
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="\?android:attr/selectableItemBackgroundBorderless"
            android:textAllCaps="false"
            android:background="?android:attr/selectableItemBackgroundBorderless" />
    </LinearLayout>
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:src="@mipmap/ic_launcher"
        android:clickable="true"
        android:background="?android:attr/selectableItemBackgroundBorderless" />
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:src="@mipmap/ic_launcher"
        android:clickable="true"
        android:background="?android:attr/selectableItemBackgroundBorderless" />
</LinearLayout>


Monday, September 21, 2015

Load animated GIF from Internet, example 2 to load new animated Google logo


Actually it is similar to the example of "Load animated GIF from Internet", but load the new animated Google logo.



com.blogspot.android_er.androidgif.GifView.java
package com.blogspot.android_er.androidgif;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Toast;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class GifView extends View{

    //Set true to use decodeStream
    //Set false to use decodeByteArray
    private static final boolean DECODE_STREAM = true;

    private InputStream gifInputStream;
    private Movie gifMovie;
    private int movieWidth, movieHeight;
    private long movieDuration;
    private long mMovieStart;

    //original source
    //final static String gifAddr = "https://lh4.googleusercontent.com/-HAx9Y7EqDgI/VendP007MKI/AAAAAAAAEpE/3pplCHO0MAA/w1044-h522-no/GD_article_sharegraphic.gif";
    //my copy of animated Google Logo
    final static String gifAddr = "http://goo.gl/ZHn9K7";
    public GifView(Context context) {
        super(context);
        init(context);
    }

    public GifView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public GifView(Context context, AttributeSet attrs,
                   int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(final Context context){
        setFocusable(true);

        gifMovie = null;
        movieWidth = 0;
        movieHeight = 0;
        movieDuration = 0;

        Thread threadLoadGif = new Thread(new Runnable(){

            @Override
            public void run() {
                try {
                    URL gifURL = new URL(gifAddr);

                    HttpURLConnection connection = (HttpURLConnection)gifURL.openConnection();
                    gifInputStream = connection.getInputStream();

                    if(DECODE_STREAM){
                        gifMovie = Movie.decodeStream(gifInputStream);
                    }else{
                        byte[] array = streamToBytes(gifInputStream);
                        gifMovie = Movie.decodeByteArray(array, 0, array.length);
                    }

                    movieWidth = gifMovie.width();
                    movieHeight = gifMovie.height();
                    movieDuration = gifMovie.duration();

                    ((MainActivity)context).runOnUiThread(new Runnable(){

                        @Override
                        public void run() {
                            //request re-draw layout
                            invalidate();
                            requestLayout();
                            Toast.makeText(context,
                                    movieWidth + " x " + movieHeight + "\n"
                                            + movieDuration,
                                    Toast.LENGTH_LONG).show();
                        }});

                } catch (MalformedURLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }});

        threadLoadGif.start();

    }

    private static byte[] streamToBytes(InputStream is) {
        ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
        byte[] buffer = new byte[1024];
        int len;
        try {
            while ((len = is.read(buffer)) >= 0) {
                os.write(buffer, 0, len);
            }
        } catch (java.io.IOException e) {
        }
        return os.toByteArray();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec,
                             int heightMeasureSpec) {
        setMeasuredDimension(movieWidth, movieHeight);
    }

    public int getMovieWidth(){
        return movieWidth;
    }

    public int getMovieHeight(){
        return movieHeight;
    }

    public long getMovieDuration(){
        return movieDuration;
    }

    @Override
    protected void onDraw(Canvas canvas) {

        long now = android.os.SystemClock.uptimeMillis();
        if (mMovieStart == 0) {   // first time
            mMovieStart = now;
        }

        if (gifMovie != null) {

            int dur = gifMovie.duration();
            if (dur == 0) {
                dur = 1000;
            }

            int relTime = (int)((now - mMovieStart) % dur);

            gifMovie.setTime(relTime);

            gifMovie.draw(canvas, 0, 0);
            invalidate();

        }

    }
}


Add <com.blogspot.android_er.androidgif.GifView> in layout file, layout/activity_main.xml
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <com.blogspot.android_er.androidgif.GifView
        android:id="@+id/gifview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" />

</LinearLayout>


Nothing to do in com.blogspot.android_er.androidgif.MainActivity.java
package com.blogspot.android_er.androidgif;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    GifView gifView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        gifView = (GifView)findViewById(R.id.gifview);
    }

}


Edit src/main/AndroidManifest.xml to add <uses-permission> of "android.permission.INTERNET", and disable hardware ccceleration by setting android:hardwareAccelerated="false".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.blogspot.android_er.androidgif" >

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:hardwareAccelerated="false" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>



download filesDownload the files (Android Studio Format) .


My copy of animated Google logo (http://goo.gl/ZHn9K7), original in https://lh4.googleusercontent.com/-HAx9Y7EqDgI/VendP007MKI/AAAAAAAAEpE/3pplCHO0MAA/w1044-h522-no/GD_article_sharegraphic.gif.

Generate SHA1 fingerprint of release keystore using keytool


To generate signed APK in Android Studio:
> Build > Generate Signed APK...

Once APK and keystore generated, you can get its SHA1 fingerprint using keytool:
keytool -exportcert -alias MyButton -keystore D:\tmp\testKeyStore\MyButton.keystore.jks -list -v
where:
MyButton is the alias.
D:\tmp\testKeyStore\MyButton.keystore.jks is the generated keystore.


related:
Locate debug.keystore and get the SHA1 fingerprint using Keytool utility

Locate debug.keystore and get the SHA1 fingerprint using Keytool utility

keytool without password by pressing [ENTER]

keytool with default password "android"
The default location of debug.keystore is in ~/.android/ on OS X and Linux, in C:\Documents and Settings\<user>\.android\ on Windows XP, and in C:\Users\<user>\.android\ on Windows Vista and Windows 7...Windows 10.

To get get the SHA1 fingerprint for debug using Keytool utility, enter the command in DOS Prompt or Terminal:
keytool -exportcert -alias androiddebugkey -keystore C:\Users\user\.android\debug.keystore -list -v
or
keytool -keystore C:\Users\user\.android\debug.keystore -list -v

You will be asked to enter password, enter default password "android" or simple ignore by pressing [ENTER].


related:
Generate SHA1 fingerprint of release keystore using keytool

Fast track your mobile success with Xamarin - Free eBook

To help developers better understand Xamarin’s complete mobile development solution, Xamarin communitytake provide a free ebook Fast Track Your Mobile Success here, in PDF format.



 know more about Build native iOS, Android and Windows apps in Visual Studio.

RippleDrawable with drawable

prev.
Touch Feedback with RippleDrawable
RippleDrawable with mask


It's a example of RippleDrawable with drawable, the ripple effect is masked against the composite of the child layers, the drawable.


drawable/rippple.xml, a simplest RippleDrawable.
<?xml version="1.0" encoding="utf-8"?>
<ripple
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#00ffff" />

drawable/ripppledrawable1.xml, RippleDrawable with drawable of "@mipmap/ic_launcher".
<?xml version="1.0" encoding="utf-8"?>
<ripple
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#ffff0000">
    <item android:drawable="@mipmap/ic_launcher" />
</ripple>

drawable/ripppledrawable2.xml, RippleDrawable with drawable of "@android:drawable/ic_menu_camera".
<?xml version="1.0" encoding="utf-8"?>
<ripple
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#ff0000ff">
    <item android:drawable="@android:drawable/ic_menu_camera" />
</ripple>

layout/activity_main.xml
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:orientation="vertical"
    android:background="#404040"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        android:clickable="true"
        android:background="@drawable/rippple" />
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:clickable="true"
        android:background="@drawable/ripppledrawable1">
    </LinearLayout>
    <LinearLayout
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:orientation="vertical"
        android:clickable="true"
        android:background="@drawable/ripppledrawable2">
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <ImageButton
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:src="@drawable/ripppledrawable2"/>
        <ImageButton
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:src="@drawable/ripppledrawable2"
            style="?android:attr/borderlessButtonStyle"/>
    </LinearLayout>


</LinearLayout>

RippleDrawable with mask


Last post show a simple example of RippleDrawable, here we add a mask to ripple. If a mask layer is set, the ripple effect will be masked against that layer before it is drawn over the composite of the remaining child layers.



drawable/rippple.xml, simple ripple without mask.
<?xml version="1.0" encoding="utf-8"?>
<ripple
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#00ffff" />

drawable/rippple2.xml, ripple with oval mask.
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
  android:color="#ff0000">
  <item android:id="@android:id/mask">
    <shape android:shape="oval">
      <solid android:color="#000000" />
    </shape>
  </item>
</ripple>

drawable/rippple3.xml, ripple with rectangle mask.
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
  android:color="#ff0000">
  <item android:id="@android:id/mask">
    <shape android:shape="rectangle">
      <solid android:color="#ffffff" />
    </shape>
  </item>
</ripple>

layout/activity_main.xml
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:orientation="vertical"
    android:background="#404040"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        android:clickable="true"
        android:background="@drawable/rippple" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <ImageView
            android:layout_height="0dp"
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:src="@mipmap/ic_launcher"
            android:clickable="true" />
        <ImageView
            android:layout_height="0dp"
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:src="@mipmap/ic_launcher"
            android:clickable="true"
            android:background="@drawable/rippple" />
        <ImageView
            android:layout_height="0dp"
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:src="@mipmap/ic_launcher"
            android:clickable="true"
            android:background="@drawable/rippple2" />
        <ImageView
            android:layout_height="0dp"
            android:layout_width="match_parent"
            android:layout_weight="1"
            android:src="@mipmap/ic_launcher"
            android:clickable="true"
            android:background="@drawable/rippple3" />
    </LinearLayout>

</LinearLayout>


Next:
- RippleDrawable with drawable

Sunday, September 20, 2015

Touch Feedback with RippleDrawable


android.graphics.drawable.RippleDrawable is a drawable that shows a ripple effect in response to state changes. Here is a simple example to show user touch with RippleDrawable.


Create file drawable/rippple.xml.
<?xml version="1.0" encoding="utf-8"?>
<ripple
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#00ffff" />

layout/activity_main.xml
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        android:clickable="true"
        android:background="@drawable/rippple" />
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@mipmap/ic_launcher"
        android:clickable="true"
        android:background="@drawable/rippple" />
</LinearLayout>


Next:
RippleDrawable with mask
- RippleDrawable with drawable

Simple buttons with drawable

Example of buttons with drawable/icon:


<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Normal Button"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="borderlessButtonStyle"
        style="?android:attr/borderlessButtonStyle"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:drawableRight="@android:drawable/ic_dialog_info"
        android:text="Normal Button with drawable"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="borderlessButtonStyle with drawable"
        android:drawableRight="@android:drawable/ic_dialog_info"
        style="?android:attr/borderlessButtonStyle"/>
    <ImageButton
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@android:drawable/ic_dialog_info"/>
    <ImageButton
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="borderlessButtonStyle"
        android:src="@android:drawable/ic_dialog_info"
        style="?android:attr/borderlessButtonStyle"/>
</LinearLayout>


Saturday, September 19, 2015

Customize color for your app, for Material Theme, using Android Studio


The new material theme provides:

  • System widgets that let you set their color palette
  • Touch feedback animations for the system widgets
  • Activity transition animations

You can customize the look of the material theme according to your brand identity with a color palette you control. You can tint the action bar and the status bar using theme attributes, as shown in Here.


reference: https://developer.android.com/training/material/theme.html

This video show how to do it in Android Studio.


Create values/colors.xml to define our custom color.
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="primary">#FFFF00</color>
    <color name="primary_dark">#502020</color>
    <color name="text_primary">#FF00ff00</color>
    <color name="text_secondary">#FFff0000</color>
    <color name="window_background">#000000</color>
    <color name="nav_color">#505050</color>
</resources>


Edit values-v21/styles.xml to use our custom color.
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AppTheme" parent="android:Theme.Material.Light">
        <item name="android:colorPrimary">@color/primary</item>
        <item name="android:colorPrimaryDark">@color/primary_dark</item>
        <item name="android:textColorPrimary">@color/text_primary</item>
        <item name="android:textColor">@color/text_secondary</item>
        <item name="android:windowBackground">@color/window_background</item>
        <item name="android:navigationBarColor">@color/nav_color</item>
    </style>
</resources>


reference: Customize the Color Palette

Friday, September 18, 2015

Open libs folder in Android Studio

Normally Android Studio will open Android on the upper left selection, you cannot find libs folder here. To find libs folder, click to switch to Project, you can locate it in >app>libs.


Wednesday, September 16, 2015

Animate Vector Drawables (AnimatedVectorDrawable) example

Vector Drawables are scalable without losing definition. The AnimatedVectorDrawable class lets you animate the properties of a vector drawable. (ref: http://developer.android.com/training/material/animations.html#AnimVector)



drawable/vectordrawable.xml
<!-- res/drawable/vectordrawable.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="64dp"
    android:width="64dp"
    android:viewportHeight="600"
    android:viewportWidth="600">
    <group
        android:name="rotationGroup"
        android:pivotX="300.0"
        android:pivotY="300.0"
        android:rotation="45.0" >
        <path
            android:name="v"
            android:fillColor="#000000"
            android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
    </group>
</vector>

drawable/animvectordrawable.xml
<!-- res/drawable/animvectordrawable.xml -->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/vectordrawable" >
    <target
        android:name="rotationGroup"
        android:animation="@anim/rotation" />
    <target
        android:name="v"
        android:animation="@anim/path_morph" />
</animated-vector>

anim/rotation.xml
<!-- res/anim/rotation.xml -->
<objectAnimator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="6000"
    android:propertyName="rotation"
    android:valueFrom="0"
    android:valueTo="360" />

anim/path_morph.xml
<!-- res/anim/path_morph.xml -->
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:duration="3000"
        android:propertyName="pathData"
        android:valueFrom="M300,70 l 0,-70 70,70 0,0   -70,70z"
        android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
        android:valueType="pathType" />
</set>

Edit layout file, layout/activity_main.xml, to include ImageViews with android:src="@drawable/animvectordrawable".
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/imageview1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/animvectordrawable"
            android:background="#D0D0D0"/>
        <ImageView
            android:id="@+id/imageview2"
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:src="@drawable/animvectordrawable"
            android:background="#B0B0B0"/>
        <ImageView
            android:id="@+id/imageview3"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/animvectordrawable"
            android:background="#909090"/>
    </LinearLayout>

</LinearLayout>


Edit MainActivity.java to start animation once clicked.
package com.blogspot.android_er.androidanimatedvectordrawable;

import android.app.Activity;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView imageView1 = (ImageView)findViewById(R.id.imageview1);
        imageView1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Drawable drawable = ((ImageView) v).getDrawable();
                ((Animatable) drawable).start();
            }
        });

        ImageView imageView2 = (ImageView)findViewById(R.id.imageview2);
        imageView2.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                Drawable drawable = ((ImageView)v).getDrawable();
                ((Animatable) drawable).start();
            }
        });

        ImageView imageView3 = (ImageView)findViewById(R.id.imageview3);
        imageView3.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                Drawable drawable = ((ImageView)v).getDrawable();
                ((Animatable) drawable).start();
            }
        });
    }

}


Related:
Vector Drawable example

Vector Drawable example

In Android 5.0 (API Level 21) and above, you can define vector drawables, which scale without losing definition.
(ref: http://developer.android.com/training/material/drawables.html#VectorDrawables)
Create vector image with the shape of a heart, drawable/heart.xml.
<!-- res/drawable/heart.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="256dp"
    android:width="56dp"
    android:viewportWidth="32"
    android:viewportHeight="32">

    <path android:fillColor="#8f00"
        android:pathData="M20.5,9.5
        c-1.955,0,-3.83,1.268,-4.5,3
        c-0.67,-1.732,-2.547,-3,-4.5,-3
        C8.957,9.5,7,11.432,7,14
        c0,3.53,3.793,6.257,9,11.5
        c5.207,-5.242,9,-7.97,9,-11.5
        C25,11.432,23.043,9.5,20.5,9.5z" />
</vector>

Use it on layout xml, layout/activity_main.xml.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/heart"
            android:background="#D0D0D0"/>

        <ImageView
            android:layout_width="150dp"
            android:layout_height="150dp"
            android:src="@drawable/heart"
            android:background="#B0B0B0"/>

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:src="@drawable/heart"
            android:background="#909090"/>

    </LinearLayout>

</LinearLayout>


next:
- Animate Vector Drawables (AnimatedVectorDrawable) example

Find addresses of given latitude and longitude using android.location.Geocoder

This example allow users to enter latitude and longitude, then find the addresses that are known to describe the area immediately surrounding the given latitude and longitude, using getFromLocation (double latitude, double longitude, int maxResults) method of android.location.Geocoder.



android.location.Geocoder is a class for handling geocoding and reverse geocoding. Geocoding is the process of transforming a street address or other description of a location into a (latitude, longitude) coordinate. Reverse geocoding is the process of transforming a (latitude, longitude) coordinate into a (partial) address. The amount of detail in a reverse geocoded location description may vary, for example one might contain the full street address of the closest building, while another might contain only a city name and postal code. The Geocoder class requires a backend service that is not included in the core android framework. The Geocoder query methods will return an empty list if there no backend service in the platform. Use the isPresent() method to determine whether a Geocoder implementation exists.



com.blogspot.android_er.androidlatlongtoaddress.MainActivity.java
package com.blogspot.android_er.androidlatlongtoaddress;

import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    Geocoder geocoder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final EditText latText = (EditText)findViewById(R.id.latText);
        final EditText lonText = (EditText)findViewById(R.id.lonText);
        Button btnFind = (Button)findViewById(R.id.find);

        final ListView listResult = (ListView)findViewById(R.id.listResult);

        geocoder = new Geocoder(this);


        btnFind.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                String strLat = latText.getText().toString();
                String strLon = lonText.getText().toString();

                boolean parsable = true;
                Double lat = null, lon = null;

                try{
                    lat = Double.parseDouble(strLat);
                }catch (NumberFormatException ex){
                    parsable = false;
                    Toast.makeText(MainActivity.this,
                            "Latitude does not contain a parsable double",
                            Toast.LENGTH_LONG).show();
                }

                 try{
                    lon = Double.parseDouble(strLon);
                }catch (NumberFormatException ex){
                    parsable = false;
                    Toast.makeText(MainActivity.this,
                            "Longitude does not contain a parsable double",
                            Toast.LENGTH_LONG).show();
                }

                if(parsable){
                    Toast.makeText(MainActivity.this,
                            "find " + lat + " : " + lon,
                            Toast.LENGTH_LONG).show();

                    List<Address> geoResult = findGeocoder(lat, lon);
                    if(geoResult != null){
                        List<String> geoStringResult = new ArrayList<String>();
                        for(int i=0; i < geoResult.size(); i++){
                            Address thisAddress = geoResult.get(i);
                            String stringThisAddress = "";
                            for(int a=0; a < thisAddress.getMaxAddressLineIndex(); a++) {
                                stringThisAddress += thisAddress.getAddressLine(a) + "\n";
                            }

                            stringThisAddress +=
                                    "CountryName: " + thisAddress.getCountryName() + "\n"
                                    + "CountryCode: " + thisAddress.getCountryCode() + "\n"
                                    + "AdminArea: " + thisAddress.getAdminArea() + "\n"
                                    + "FeatureName: " + thisAddress.getFeatureName();
                            geoStringResult.add(stringThisAddress);
                        }

                        ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this,
                                android.R.layout.simple_list_item_1, android.R.id.text1, geoStringResult);

                        listResult.setAdapter(adapter);
                    }

                }

            }
        });
    }

    private List<Address> findGeocoder(Double lat, Double lon){
        final int maxResults = 5;
        List<Address> addresses = null;
        try {
            addresses = geocoder.getFromLocation(lat, lon, maxResults);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }

        return addresses;
    }

}


layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <EditText
        android:id="@+id/latText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="numberSigned|numberDecimal"
        android:hint="Latitude" />

    <EditText
        android:id="@+id/lonText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="numberSigned|numberDecimal"
        android:hint="Longitude" />

    <Button
        android:id="@+id/find"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="find Address"/>

    <ListView
        android:id="@+id/listResult"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>


download filesDownload the files (Android Studio Format) .

Related:
- Get ISO country code for the given latitude/longitude, using GeoNames Web Service

Tuesday, September 15, 2015

Add external JAR as library in Android Studio, org.apache.http


This video show how to add external JAR as library module in Android Studio, org.apache.http as a example.


Android Studio, Create New Module cannot access "Next" button - fixed

The case is: I have to create new module in Android Studio, but the Create New Module window is too high, I cannot access the Next button. To fix it, click on the upper-left icon to re-size the window and widen it, such that I can click on the Next button.



Monday, September 14, 2015

Generate device artwork using Device Art Generator


The Device Art Generator enables you to quickly wrap app screenshots in device artwork. This provides better visual context for your app screenshots on your website or in other promotional materials.

Visit Device Art Generator:
Drag a screenshot from your desktop onto a device to generate device art.

Sunday, September 13, 2015

Android pre-defined Button style - buttonStyle, borderlessButtonStyle, buttonStyleToggle and buttonStyleInset


Some example of pre-defined Button style, include buttonStyle, borderlessButtonStyle, buttonStyleToggle and buttonStyleInset.


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="buttonStyle: Normal Button style"
        style="?android:attr/buttonStyle"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="borderlessButtonStyle: Style for buttons without an explicit border"
        style="?android:attr/borderlessButtonStyle"/>

    <ToggleButton
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textOn="ON - buttonStyleToggle: ToggleButton style"
        android:textOff="OFF - buttonStyleToggle: ToggleButton style"
        style="?android:attr/buttonStyleToggle"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="buttonStyleInset: Button style to inset into an EditText"
        style="?android:attr/buttonStyleInset"/>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button android:id="@+id/id_EditText_Button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:text="OK"
            style="?android:attr/buttonStyleInset"/>
        <EditText
            android:id="@+id/id_EditText"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignTop="@+id/id_EditText_Button"
            android:layout_alignBottom="@+id/id_EditText_Button"
            android:layout_alignParentLeft="true"
            android:layout_toLeftOf="@id/id_EditText_Button"
            android:singleLine="true"
            android:hint="Enter Something" />

    </RelativeLayout>

</LinearLayout>




Related:
- Custom Color Button

Saturday, September 12, 2015

Create custom color button, in Android Studio


To create custom buton, create a XML file under drawable folder.


drawable/colorbutton.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape>
            <gradient
                android:angle="90"
                android:endColor="#000050"
                android:startColor="#0000E0" />
            <stroke
                android:width="3dp"
                android:color="#303030" />
            <corners
                android:radius="10dp" />
            <padding
                android:bottom="10dp"
                android:left="10dp"
                android:right="10dp"
                android:top="10dp" />
        </shape>
    </item>

    <item android:state_focused="true">
        <shape>
            <gradient
                android:angle="270"
                android:endColor="#500000"
                android:startColor="#E00000" />
            <stroke
                android:width="3dp"
                android:color="#303030" />
            <corners
                android:radius="10dp" />
            <padding
                android:bottom="10dp"
                android:left="10dp"
                android:right="10dp"
                android:top="10dp" />
        </shape>
    </item>

    <item>
        <shape>
            <gradient
                android:angle="270"
                android:endColor="#005050"
                android:startColor="#00E0E0" />
            <stroke
                android:width="3dp"
                android:color="#303030" />
            <corners
                android:radius="10dp" />
            <padding
                android:bottom="10dp"
                android:left="10dp"
                android:right="10dp"
                android:top="10dp" />
        </shape>
    </item>
</selector>

Use it in layout file, layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Color Button"
        android:background="@drawable/colorbutton"
        android:textColor="@android:color/white"/>

</LinearLayout>



How to do it in Android Studio:




Related:
- Android pre-defined Button style - buttonStyle, borderlessButtonStyle, buttonStyleToggle and buttonStyleInset