Friday, March 15, 2019

Android Jetpack: Introducing Navigation Component

The Navigation component is a suite of libraries, tooling and guidance for in-app navigation. The component centralizes all of the navigation information of your app in a navigation graph, providing a robust framework for implementing everything from simple button clicks to complex navigation UI patterns.


Android Studio 3.3 includes the Navigation Editor, which visuals your navigation graph. Other features and benefits include:

- Automatic handling of fragment transactions
- Correctly handling up and back
- Default behaviors for animations and transitions
- Deep linking, including proper backstack generation
- Implementing common patterns like navigation drawers and bottom nav with little additional work using the Navigation UI library → http://bit.ly/2EWYtoV
- Type safety when passing information while navigating using the Safe Args plugin → http://bit.ly/2VR7kPM

To learn more about Navigation, check out:

- The Navigation Component Documentation → http://bit.ly/2TJuhao
- Navigation Codelab → http://bit.ly/2TSa9mB
- Single Activity: Why, When, and How at Android Dev Summit '18 → http://bit.ly/2u5OoRC
- Android Studio 3.3 Blogpost → http://bit.ly/2VWxJMc
- Base Navigation Reference Documentation → http://bit.ly/2EY0Mbn
- Fragment navigation Reference Documentation → http://bit.ly/2UB0ltY
- Navigation UI Reference Documentation → http://bit.ly/2FbXKBL
- Source code (part of AOSP) → http://bit.ly/2UBbHOG
- Navigation Editor Issue Tracker → http://bit.ly/2VWvrws
- Navigation Component Issue Tracker (Non Navigation Editor) → http://bit.ly/2CjXazR


Wednesday, March 13, 2019

Add Google Maven repository to Android Studio Project

With latest Android Studio, I change the targetSdkVersion and compileSdkVersion of my old exercise to 28. And I also have to use updated com.android.support:appcompat-v7 and com.android.support.constraint:constraint-layout. After fail in rebuild, it's a number of WARNING and ERROR.

-----------------------------
ERROR: Failed to resolve: com.android.support:appcompat-v7:28.0.0
Add Google Maven repository and sync project
Show in Project Structure dialog
Affected Modules: app

ERROR: Failed to resolve: com.android.support.constraint:constraint-layout:1.1.3
Add Google Maven repository and sync project
Show in Project Structure dialog
Affected Modules: app

WARNING: Configuration 'compile' is obsolete and has been replaced with 'implementation' and 'api'.
It will be removed at the end of 2018. For more information see: http://d.android.com/r/tools/update-dependency-configurations.html
Affected Modules: app

WARNING: Configuration 'testCompile' is obsolete and has been replaced with 'testImplementation'.
It will be removed at the end of 2018. For more information see: http://d.android.com/r/tools/update-dependency-configurations.html
Affected Modules: app

WARNING: Configuration 'androidTestCompile' is obsolete and has been replaced with 'androidTestImplementation'.
It will be removed at the end of 2018. For more information see: http://d.android.com/r/tools/update-dependency-configurations.html
Affected Modules: app
-----------------------------

As suggested, I change  'compile', 'testCompile' and 'androidTestCompile' to 'implementation', 'testImplementation' and 'androidTestImplementation', in app/build.gradle.


To fix the error of Failed to resolve: com.android.support:appcompat-v7:28.0.0 and com.android.support.constraint:constraint-layout:1.1.3, I add the follow lines of Google Maven repository to build.gradle.

        maven {
            url 'https://maven.google.com/'
            name 'Google'
        }



And rebuild the project. At least it works for me now.




So, how to know the latest version of com.android.support:appcompat-v7 and com.android.support.constraint:constraint-layout?

For Support Library, you can check here: Android Developers > Platform > Libraries > Recent Support Library Revisions

28.0.0 is the recentest stable release of Support Library released on September 21, 2018 and will be the last feature release under the android.support packaging.

For ConstraintLayout, Google announced at https://androidstudio.googleblog.com/2018/08/constraintlayout-113.html.

You can also check from Maven repository:
>> com.android.support >> appcompat-v7
>> com.android.support.constraint >> constraint-layout


Sunday, March 10, 2019

What is "android.R.layout.simple_list_item_1"?

Sometimes you will find some predefined layout in other examples, such as android.R.layout.simple_list_item_1 like this:

        String[] suggestion = getResources().getStringArray(R.array.suggestion);
        ArrayAdapter<String> adapter =
                new ArrayAdapter<String>(this,
                        android.R.layout.simple_list_item_1, suggestion);

It's a reference to built-in XML layout that is part of the Android OS, HERE. Basically, all reference start with android.R is reference to Android built-in resource.

You can locate the source file in your development setup from Android Studio (BUT DON'T EDIT IT):


> Select it and right click > Go to > Declaration
Android Studio will open it for you, and the location will be shown on top bar.


Saturday, March 9, 2019

Write image to External Storage with Permission Request at runtime, for Android 6+

It's a simple example to write image to External Storage, with targetSdkVersion = 28. It work as expected on devices running Android below 6, but fail on Android 6+! (Solution provided in second part below)



Java code:
package com.blogspot.android_er.androidwriteimage;

import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MainActivity extends AppCompatActivity {

    final String MyAlbum = "android-er";
    Bitmap bitmapSrc;
    TextView tvSavedInfo;

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

        tvSavedInfo = (TextView)findViewById(R.id.savedinfo);

        dispTestCase();

        //prepare dummy source of bitmap to save
        Drawable drawable = getDrawable(R.mipmap.ic_launcher);
        bitmapSrc = BitmapFactory.decodeResource(
                getApplicationContext().getResources(),
                R.mipmap.ic_launcher);

        ImageView ivImage;
        ivImage = findViewById(R.id.imageView1);
        ivImage.setImageDrawable(drawable);

        Button btnSave;
        btnSave = (Button)findViewById(R.id.buttonSave);
        btnSave.setOnClickListener(btnOnClickListener);

    }

    public File getPublicAlbumStorageDir(String albumName) {
    // Get the directory for the user's public pictures directory.
        File file = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES), albumName);
        if (file.mkdirs()) {
            //if directory not exist
            Toast.makeText(getApplicationContext(),
                    file.getAbsolutePath() + " created",
                    Toast.LENGTH_LONG).show();
        }else{
            Toast.makeText(getApplicationContext(),
                    "Directory not created", Toast.LENGTH_LONG).show();
        }
        return file;
    }

    Button.OnClickListener btnOnClickListener = new Button.OnClickListener(){

        @Override
        public void onClick(View v) {

            tvSavedInfo.setText("");
            writeImage();

        }
    };

    private void writeImage(){
        //generate a unique file name from timestamp
        Date date = new Date();
        SimpleDateFormat simpleDateFormat =
                new SimpleDateFormat("yyMMdd-hhmmss-SSS");
        String fileName = "img" + simpleDateFormat.format(new Date()) + ".jpg";

        File dir = getPublicAlbumStorageDir(MyAlbum);
        File file = new File(dir, fileName);

        OutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(file);
            bitmapSrc.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);
            outputStream.flush();
            outputStream.close();

            tvSavedInfo.setText("File saved: \n" + file.getAbsolutePath());

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Toast.makeText(getApplicationContext(),
                    "FileNotFoundException: \n" + e.getMessage(),
                    Toast.LENGTH_LONG).show();
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(getApplicationContext(),
                    "IOException: \n" + e.getMessage(),
                    Toast.LENGTH_LONG).show();
        }
    }

    private void dispTestCase(){
        String testCase;

        TextView tvTestCase;
        tvTestCase = (TextView)findViewById(R.id.testcase);
        testCase = "Tested on Android " + Build.VERSION.RELEASE + "\n";


        PackageManager packageManager = getPackageManager();
        String packageName = getPackageName();
        int targetSdkVersion;
        try {
            PackageInfo packageInfo =
                    packageManager.getPackageInfo(packageName, 0);

            ApplicationInfo applicationInfo = packageInfo.applicationInfo;
            targetSdkVersion = applicationInfo.targetSdkVersion;

            testCase += "targetSdkVersion = " + targetSdkVersion;

        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            Toast.makeText(getApplicationContext(),
                    "NameNotFoundException: " + e.getMessage(),
                    Toast.LENGTH_LONG).show();
        }

        tvTestCase.setText(testCase);

    }

}


Layout XML:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="10dp"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/addr"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:text="android-er.blogspot.com"
        android:textSize="20dp"
        android:textStyle="italic"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Write Image to External Storage"
        android:textSize="26dp"
        android:textStyle="bold"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/addr" />

    <TextView
        android:id="@+id/testcase"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="26dp"
        android:textColor="#A00000"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/title"/>

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/testcase" />
    <TextView
        android:id="@+id/savedinfo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/imageView1"/>

    <Button
        android:id="@+id/buttonSave"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click to save"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/savedinfo" />

</android.support.constraint.ConstraintLayout>


uses-permission of "android.permission.WRITE_EXTERNAL_STORAGE" is needed in manifest.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.blogspot.android_er.androidwriteimage">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

reference:
- Android Developers > Docs > Guides > Save files on device storage


Request Permission at runtime:

The above code fail when install on device running Android 6+! Because start from Android 6, your apps have to request user approve permissions at runtime. The following example show how to check and request permission at runtime. You still have to declare uses-permission of "android.permission.WRITE_EXTERNAL_STORAGE" in manifest.

When run on devices below Android 6, permission will be granted at install time. When run on Android 6+, you have to check permission at runtime before perform the task and ask user for approval if need.



package com.blogspot.android_er.androidwriteimage;

import android.Manifest;
import android.app.Activity;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MainActivity extends AppCompatActivity {

    final String MyAlbum = "android-er";
    Bitmap bitmapSrc;
    TextView tvSavedInfo;

    Activity thisActivity;
    final int MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1;

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

        thisActivity = this;

        tvSavedInfo = (TextView)findViewById(R.id.savedinfo);

        dispTestCase();

        //prepare dummy source of bitmap to save
        Drawable drawable = getDrawable(R.mipmap.ic_launcher);
        bitmapSrc = BitmapFactory.decodeResource(
                getApplicationContext().getResources(),
                R.mipmap.ic_launcher);

        ImageView ivImage;
        ivImage = findViewById(R.id.imageView1);
        ivImage.setImageDrawable(drawable);

        Button btnSave;
        btnSave = (Button)findViewById(R.id.buttonSave);
        btnSave.setOnClickListener(btnOnClickListener);

    }

    public File getPublicAlbumStorageDir(String albumName) {
        // Get the directory for the user's public pictures directory.
        File file = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES), albumName);
        if (file.mkdirs()) {
            //if directory not exist
            Toast.makeText(getApplicationContext(),
                    file.getAbsolutePath() + " created",
                    Toast.LENGTH_LONG).show();
        }else{
            Toast.makeText(getApplicationContext(),
                    "Directory not created", Toast.LENGTH_LONG).show();
        }
        return file;
    }

    Button.OnClickListener btnOnClickListener = new Button.OnClickListener(){

        @Override
        public void onClick(View v) {

            tvSavedInfo.setText("");

            if (ContextCompat.checkSelfPermission(thisActivity,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    != PackageManager.PERMISSION_GRANTED) {
                // Permission is not granted
                // Should we show an explanation?
                if (ActivityCompat.shouldShowRequestPermissionRationale(
                        thisActivity,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                    // Show an explanation to the user *asynchronously* -- don't block
                    // this thread waiting for the user's response! After the user
                    // sees the explanation, try again to request the permission.

                    //to simplify, call requestPermissions again
                    Toast.makeText(getApplicationContext(),
                            "shouldShowRequestPermissionRationale",
                            Toast.LENGTH_LONG).show();
                    ActivityCompat.requestPermissions(thisActivity,
                            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                            MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
                } else {
                    // No explanation needed; request the permission
                    ActivityCompat.requestPermissions(thisActivity,
                            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                            MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
    }
            }else{
                // permission granted
                writeImage();
            }

        }
    };

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {

        if(requestCode == MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE){
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // permission was granted.
                Toast.makeText(getApplicationContext(),
                        "permission was granted, thx:)",
                        Toast.LENGTH_LONG).show();
            } else {
                // permission denied.
                Toast.makeText(getApplicationContext(),
                        "permission denied! Oh:(",
                        Toast.LENGTH_LONG).show();
            }
            return;
        }else{
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    private void writeImage(){
        //generate a unique file name from timestamp
        Date date = new Date();
        SimpleDateFormat simpleDateFormat =
                new SimpleDateFormat("yyMMdd-hhmmss-SSS");
        String fileName = "img" + simpleDateFormat.format(new Date()) + ".jpg";

        File dir = getPublicAlbumStorageDir(MyAlbum);
        File file = new File(dir, fileName);

        OutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(file);
            bitmapSrc.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);
            outputStream.flush();
            outputStream.close();

            tvSavedInfo.setText("File saved: \n" + file.getAbsolutePath());

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Toast.makeText(getApplicationContext(),
                    "FileNotFoundException: \n" + e.getMessage(),
                    Toast.LENGTH_LONG).show();
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(getApplicationContext(),
                    "IOException: \n" + e.getMessage(),
                    Toast.LENGTH_LONG).show();
        }
    }

    private void dispTestCase(){
        String testCase;

        TextView tvTestCase;
        tvTestCase = (TextView)findViewById(R.id.testcase);
        testCase = "Tested on Android " + Build.VERSION.RELEASE + "\n";


        PackageManager packageManager = getPackageManager();
        String packageName = getPackageName();
        int targetSdkVersion;
        try {
            PackageInfo packageInfo =
                    packageManager.getPackageInfo(packageName, 0);

            ApplicationInfo applicationInfo = packageInfo.applicationInfo;
            targetSdkVersion = applicationInfo.targetSdkVersion;

            testCase += "targetSdkVersion = " + targetSdkVersion;

        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            Toast.makeText(getApplicationContext(),
                    "NameNotFoundException: " + e.getMessage(),
                    Toast.LENGTH_LONG).show();
        }

        tvTestCase.setText(testCase);

    }

}


Layout XML file is same as above.

reference:
- Android Developers > Docs > Guides > Request App Permissions


Thursday, March 7, 2019

Get targetSdkVersion, minSdkVersion, versionName and versionCode at runtime

We can retrieve targetSdkVersion, minSdkVersion, versionName and versionCode from PackageInfo and ApplicationInfo.


Java code:
package com.blogspot.android_er.androidgetmodelinfo;

import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

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

        TextView tvInfo, tvSdkInfo;
        tvInfo = (TextView)findViewById(R.id.info);
        tvSdkInfo = (TextView)findViewById(R.id.sdkinfo);

        String manufacturer = Build.MANUFACTURER;
        String model = Build.MODEL;
        String release = Build.VERSION.RELEASE;;

        tvInfo.setText(
                manufacturer + "\n"
                + model + "\n"
                + "Android: " + release + "\n");

        PackageManager packageManager = getPackageManager();
        String packageName = getPackageName();
        int targetSdkVersion, minSdkVersion;
        int versionCode;
        String versionName;
        try {
            PackageInfo packageInfo =
                    packageManager.getPackageInfo(packageName, 0);

            /*
            versionCode was deprecated in API level 28.
            Use getLongVersionCode() instead, which includes both this
            and the additional versionCodeMajor attribute. The version
            number of this package, as specified by the <manifest>
            tag's versionCode attribute.
             */
            versionCode = packageInfo.versionCode;
            versionName = packageInfo.versionName;

            ApplicationInfo applicationInfo = packageInfo.applicationInfo;

            /*
            targetSdkVersion added in API level 4
            minSdkVersion added in API level 24
             */
            targetSdkVersion = applicationInfo.targetSdkVersion;
            minSdkVersion = applicationInfo.minSdkVersion;

            tvSdkInfo.setText("targetSdkVersion = " + targetSdkVersion + "\n"
                            + "minSdkVersion = " + minSdkVersion + "\n"
                            + "versionCode: " + versionCode + "\n"
                            + "versionName: " + versionName);


        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            Toast.makeText(getApplicationContext(),
                    "NameNotFoundException: " + e.getMessage(),
                    Toast.LENGTH_LONG).show();
        }



    }
}



Layout XML
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="5dp"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/addr"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:text="android-er.blogspot.com"
        android:textSize="20dp"
        android:textStyle="italic"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Get device Model info"
        android:textSize="24dp"
        android:textStyle="bold"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/addr" />
    <TextView
        android:id="@+id/info"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="24dp"
        android:textColor="#D00000"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/title"/>
    <TextView
        android:id="@+id/sdkinfo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="24dp"
        android:textColor="#0000D0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/info"/>

</android.support.constraint.ConstraintLayout>

Get manufacturer, model and OS version of your Android devices


android.os.Build provide various information about the current build the devices, extracted from system properties. here is a simple example to get the manufacturer and model of the device, and the version of the Android.

Java code:
package com.blogspot.android_er.androidgetmodelinfo;

import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

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

        TextView tvInfo;
        tvInfo = (TextView)findViewById(R.id.info);

        String manufacturer = Build.MANUFACTURER;
        String model = Build.MODEL;
        String release = Build.VERSION.RELEASE;;

        tvInfo.setText(
                manufacturer + "\n"
                + model + "\n"
                + "Android: " + release + "\n");

    }
}


layout XML
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="5dp"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/addr"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:text="android-er.blogspot.com"
        android:textSize="20dp"
        android:textStyle="italic"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Get device Model info"
        android:textSize="24dp"
        android:textStyle="bold"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/addr" />
    <TextView
        android:id="@+id/info"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="24dp"
        android:textColor="#D00000"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/title"/>

</android.support.constraint.ConstraintLayout>

Tested on:
Samsung Galaxy A9, SM-A9000
Xiaomi's Redmi Note 4

Next:
Get targetSdkVersion, minSdkVersion, versionName and versionCode at runtime

Kotlin is 3 years old!

Kotlin is 3 years old! Let’s take a moment to look back at it all.


Sunday, March 3, 2019

Kotlin online playground

It's a good web to try Kotlin for beginner, Kotlin Playground, an online sandbox to explore Kotlin
programming language. You can edit, run and share Kotlin code online, and also browse code samples directly in the browser.

visit: https://play.kotlinlang.org/