Thursday, December 19, 2019

Link your phone and Windows PC, using Microsoft Your Phone Companion app

With Your Phone Companion you can easily sync your Android phone with your Windows 10 PC. Get instant access to everything you love on your phone, right on your PC. Reply to your text messages with ease, stop emailing yourself photos, and receive your phone's notifications on your PC's bigger screen.

Your Phone Companion features:

Connect your phone and PC
• Receive and manage your Android phone's notifications on your PC
• Read and reply to your text messages from your PC
• Photos taken on your phone are instantly available on your PC

To use it, install Your Phone Companion app on your Android phone and Your Phone program on your Windows PC.


Thursday, October 24, 2019

Android Dev Summit '19 keynote


Event keynote featuring Dave Burke, VP of Engineering and Steph Cuthbertson, Senior Director of Product Management.

Presented by: Dave Burke, Stephanie Cuthbertson, Tian Lim, Romain Guy, Karen Ng

Android Dev Summit '19 all sessions playlist > https://goo.gle/ADS19allsessions

Wednesday, October 16, 2019

Kivy on Android

Kivy is a open source Python library for rapid development, runs on Linux, Windows, OS X, Android, iOS, and Raspberry Pi. You can run the same code on all supported platforms.

You can run Kivy applications on Android, on (more or less) any device with OpenGL ES 2.0 (Android 2.2 minimum). This is standard on modern devices; Google reports the requirement is met by 99.9% of devices.

Kivy APKs are normal Android apps that you can distribute like any other, including on stores like the Play store. They behave properly when paused or restarted, may utilise Android services and have access to most of the normal java API.

~ know more

Monday, September 9, 2019

Huawei's IFA 2019 press conference, introduce the world's first 5G SoC; Kirin 990


Here at IFA 2019, Huawei introduced the world's first 5G system on a chip; the Kirin 990. The company also showed off a new set of truly wireless earbuds, featuring wireless charging, and active noise cancellation.

Sunday, September 1, 2019

Huawei launched official website for Ark Compiler, 方舟编译器

Huawei launched official website for Ark Compiler (方舟编译器) on August 31.  The Open Ark Compiler, Huawei’s application compiler, works to improve the compilation efficiency of Android apps by  directly interpreting and executing the machine code/binary code to the system language target HarmonyOS.

Currently, The Ark Compiler web site is in Chinese only.The English version of the website will go live in Q4 2019.


#Huawei #ArkCompiler #openarkcompiler

Monday, May 27, 2019

Kotlin Collections Overview

Collections are a common concept for most programming languages. The Kotlin Standard Library provides a comprehensive set of tools for managing collections – groups of a variable number of items (possibly zero) that share significance to the problem being solved and are operated upon commonly.

Check the ultimate guide, Kotlin Collections Overview, with 18 sections that cover everything from the basic essentials to mastery.

Wednesday, May 22, 2019

Google teamed up with udacity to bring a free online cource for Developing Android Apps with Kotlin

The free online course Developing Android Apps with Kotlin, was developed by Google with Udacity. You'll learn how to build Android apps using industry-standard tools and libraries in the Kotlin programming language.

In this free course, you will learn the fundamentals of building Android applications using Kotlin. The course covers architecture components, multi-screen navigation, data persistence, RESTful APIs and Material Design. By the end of the course, you’ll be able to create well-designed Android applications using Kotlin that can connect to the internet, store data and navigate between screens.

detail: Udacity FREE COURSE : Developing Android Apps with Kotlin by Google


Saturday, May 18, 2019

Android development become increasingly Kotlin-first

At Google I/O'19, Google announced Android development will become increasingly Kotlin-first. Many new Jetpack APIs and features will be offered first in Kotlin. If you’re starting a new project, you should write it in Kotlin.

What's New in Kotlin on Android, 2 Years In (Google I/O'19)
This session examines the progress made in Android support for Kotlin. This talk will cover Kotlin samples and reference docs, annotations, framework APIs, IDE support for low-level bytecode optimizations in the D8/R8 compiler, and work on the Kotlin Foundation.

Monday, May 6, 2019

Modern Android development: Android Jetpack, Kotlin, and more

This recommended video from Google I/O 2018 help developers understand how new APIs and features work together and learn what should use to build solid, modern Android applications.


Monday, April 8, 2019

Enable USB 2.0/3.0 supported for VirtualBox

By default, Oracle VirtualBox support USB 1.1 only. This video show how to enable USB 2.0/3.0 for VirtualBox 6.0.4/Windows 10 by installing VirtualBox Extension Pack.


Visit VirtualBox Downloads page, scroll down to download and install VirtualBox 6.0.4 Oracle VM VirtualBox Extension Pack.

Support for USB 2.0 and USB 3.0 devices, VirtualBox RDP, disk encryption, NVMe and PXE boot for Intel cards. See this chapter from the User Manual for an introduction to this Extension Pack. The Extension Pack binaries are released under the VirtualBox Personal Use and Evaluation License (PUEL). Please install the same version extension pack as your installed version of VirtualBox.




Thursday, April 4, 2019

Android Q Beta 2 Announced



Android Q beta 2 contains stronger protections for user privacy along with new ways to engage users including bubbles. Dan Galpin highlights many of the changes in both the Q beta 1 and 2 releases,  including extended support for foldables, faster ShareSheets with updated direct sharing, and high performance features such as Vulkan 1.1.  Android Q beta 2 is now available on all Pixel devices.

More about the Android Q Developer Preview: https://d.android.com/preview

Get the Android Q Developer Preview: https://www.google.com/android/beta

Read the Android Q Beta 2 post here → https://android-developers.googleblog.com/2019/04/android-q-beta-2-update.html

More info on Cloud-Based ART Profiles → https://android-developers.googleblog.com/2019/04/improving-app-performance-with-art.html



Added@2019-05-06

How to Install Android Q Beta

Android Preview website → https://goo.gle/2LiT8id
Android Q release notes → https://goo.gle/2V0bsfA
Android Q Preview feedback channel → https://goo.gle/2Wp8tPs


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/



Monday, February 25, 2019

How to set Java version in Android Studio

The video show how to set Java version on Studio 3.3.1.



By default, the Java language version used to compile your project is based on your project's compileSdkVersion (because different versions of Android support different versions of Java). If necessary, you can override this default Java version by adding the following CompileOptions {} block to your build.gradle file:

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_6
        targetCompatibility JavaVersion.VERSION_1_6
    }
}

(reference: Android Developers > Android Studio > User guide > Set the JDK version)

You can also set using Android Studio menu:
- File > Project Structure.
- In Structure Project dialog, Select App on the left, and select Properties tab.
- You can see option boxes of Source Compatibility and Target Compatibility).



sourceCompatibility vs targetCompatibility

According to Gradle documentation:

  • JavaVersion sourceCompatibility - Java version compatibility to use when compiling Java source. Default value: version of the current JVM in use JavaVersion. Can also set using a String or a Number, e.g. '1.5' or 1.5.
  • JavaVersion targetCompatibility - Java version to generate classes for. Default value: sourceCompatibility. Can also set using a String or Number, e.g. '1.5' or 1.5.

(reference: https://docs.gradle.org/current/userguide/java_plugin.html)

Sunday, February 24, 2019

Google Play will require new/update App to target API level 28+ in 2019

Google Play Console will continue to require that apps target a recent API level:

  • August 2019: New apps are required to target API level 28 (Android 9) or higher.
  • November 2019: Updates to existing apps are required to target API level 28 or higher.

Existing apps that are not receiving updates are unaffected and can continue to be downloaded from the Play Store.

source: Android Developer Blog - Expanding target API level requirements in 2019


Thursday, February 21, 2019

Install JetBrains Toolbox App on Linux, and also Android Studio and IntelliJ IDEA (Java IDE)

JetBrains Toolbox App is a lightweight cross-platform companion application for JetBrains' coding tools, to manage installed tools, download new ones and open recent projects.

System requirement to install Toolbox App for Linux:
64-bit x86, glibc 2.17 (Ubuntu 14.04 or newer). JetBrains Toolbox App is packaged in AppImage and requires FUSE to run.

To check the version of your glibc, it's a simple method, using ldd command in Terminal:
$ ldd --version

It will show something like this:
ldd (Ubuntu GLIBC 2.27-3ubuntu1) 2.27

To install and set FUSE, follow the steps in AppImage Wiki.

For Ubuntu, enter the commands in Terminal:

$ sudo apt install fuse
$ sudo modprobe fuse
$ sudo groupadd fuse
$ user="$(whoami)"
$ sudo usermod -a -G fuse $user

Visit https://www.jetbrains.com/toolbox/app/ to download the, currently it's version 1.13.

This video show how to Install JetBrains Toolbox App on Linux Mint 19.1

Install Android 3.3.1 on Linux Mint 19.1 with JetBrains Toolbox, Hello World and convert Java to Kotlin.

IntelliJ IDEA (Java IDE) with JetBrains Toolbox.

Wednesday, February 20, 2019

Install OpenJDK on Linux Mint/Ubuntu

OpenJDK (https://openjdk.java.net/) provides open-source builds of the Java Development Kit, an implementation of the Java SE Platform under the GNU General Public License, version 2, with the Classpath Exception.

Commercial builds of JDK from Oracle under a non-open-source license, for a wider range of platforms, can be found at the Oracle Technology Network.

This video show how to Install OpenJDK 11.0.2 on Linux Mint 19.1. The OpenJDK will be stored in /opt/java directory, and set as default. It should be work on other Ubuntu variants also.


Oracle's OpenJDK JDK binaries for Windows, macOS, and Linux are available on release-specific pages of jdk.java.net as .tar.gz or .zip archives.

As an example, the archives for JDK 11 (currently 11.0.2) may be found on https://jdk.java.net/11/.

- Visit https://jdk.java.net/11/ to download Linux / x64 build.

- Change to the downloaded directory, it's ~/Downloads in my case.

- Extract the downloaded file, openjdk-11.0.2_linux-x64_bin.tar.gz.
$ tar -zxvf openjdk-11.0.2_linux-x64_bin.tar.gz

-  Create a folder in /opt/java where jdk will be stored.
$ sudo mkdir -p /opt/java

- Move the extracted folder to /opt/java
$ sudo mv jdk-11.0.2 /opt/java

- Set default java and javac using update-alternatives:
$ sudo update-alternatives --install /usr/bin/javac javac /opt/java/jdk-11.0.2/bin/javac 1
$ sudo update-alternatives --install /usr/bin/java java /opt/java/jdk-11.0.2/bin/java 1
$ sudo update-alternatives --config javac
$ sudo update-alternatives --config java

There are 2 choices for the alternative java, enter the selection of "1", corresponding to the number of /opt/java/jdk-11.0.2/bin/java.



may be interested:
Install JetBrains Toolbox App on Linux, and also Android Studio and IntelliJ IDEA (Java IDE)

Monday, February 11, 2019

My first exercise of using Data Binding + ObservableField

The Data Binding Library is a support library that allows you to bind UI components in your layouts to data sources in your app using a declarative format rather than programmatically. It's my first exercise of using Data Binding and ObservableField, in Java. Basically, it follow the steps in Android Developers document of Data Binding Library.


The TextViews myArchitecture, myRelease and myDensity are loaded in onCreate() once. The TextView myNumber is associated with ObservableField, and will be updated at run-time.

Prepare:

- To use the Data Binding Library in your app, you have to target devices running Android 4.0 (API level 14) or higher.

- It's recommended to use the latest Android Plugin for Gradle in your project. Currently it's 3.3.1.


Read this video how to:

- Make sure include Support Repository in the Android SDK manager.


-  Add the dataBinding element to your build.gradle file in the app module.

In Android Studio, select Project view, extend app view, select to edit build.gradle. Add the code:

    dataBinding {
        enabled = true
    }


- Enable the new data binding compiler.
Note: The new compiler in Android Plugin version 3.2 is enabled by default. (refer https://developer.android.com/topic/libraries/data-binding/start) So it's skipped here.

- layout:
layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable name="user" type="com.blogspot.android_er.myandroidinfo.MainActivity.User"/>
    </data>

    <android.support.constraint.ConstraintLayout
        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"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="My device info"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:textStyle="bold"/>
        <TextView
            android:id="@+id/mylink"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="android-er.blogspot.com"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/title" />
        <TextView
            android:id="@+id/myArchitecture"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text='@{user.bArchitecture, default="Architecture"}'
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/mylink"
            android:gravity="left"
            android:textSize="30dp"/>
        <TextView
            android:id="@+id/myRelease"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text='@{user.bRelease, default="Release"}'
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/myArchitecture"
            android:gravity="left"
            android:textSize="30dp"/>
        <TextView
            android:id="@+id/myDensity"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text='@{user.bDensity, default="Density"}'
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/myRelease"
            android:gravity="left"
            android:textSize="30dp"/>

        <TextView
            android:id="@+id/myNumber"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{user.bNum}"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/myDensity"
            android:gravity="left"
            android:textSize="50dp"
            android:textStyle="italic|bold"
            android:textColor="#0000FF"/>

    </android.support.constraint.ConstraintLayout>
</layout>

- Java code
MainActivity.java
package com.blogspot.android_er.myandroidinfo;

import android.databinding.DataBindingUtil;
import android.databinding.ObservableField;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;

import com.blogspot.android_er.myandroidinfo.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

    public class User {
        public final String bArchitecture;
        public final String bRelease;
        public final String bDensity;
        public final ObservableField<String> bNum = new ObservableField<>();
        public User(String arch, String rel, String den) {
            this.bArchitecture = arch;
            this.bRelease = rel;
            this.bDensity = den;
        }
    }

    private class MyTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... voids) {

            for (int i = 0; i < 20; i++) {
                user.bNum.set(String.valueOf(i));
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    }

    User user;

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

        String arch = System.getProperty("os.arch");
        String release = Build.VERSION.RELEASE;

        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        int dpi = metrics.densityDpi;

        ActivityMainBinding binding =
                DataBindingUtil.setContentView(this, R.layout.activity_main);
        user = new User(arch, release, String.valueOf(dpi));
        binding.setUser(user);

        new MyTask().execute();

    }
}


Sunday, February 10, 2019

Change Gradle plugin version in Android Studio 3.3.1

To change Gradle plugin to specified version, you can:
- the File > Project Structure > Project menu in Android Studio,


- or edit the top-level build.gradle file.

Tuesday, February 5, 2019

Get Architecture, Version and Screen DPI programmatically

This code get Architecture, Version and Screen DPI of Android device programmatically, using Java.


package com.blogspot.android_er.myandroidinfo;

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

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tvMyArch = findViewById(R.id.myArchitecture);
        TextView tvMyRelease = findViewById(R.id.myRelease);
        TextView tvMyDensity = findViewById(R.id.myDensity);

        String arch = System.getProperty("os.arch");
        tvMyArch.setText(arch);

        String release = Build.VERSION.RELEASE;
        tvMyRelease.setText(release);

        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        int dpi = metrics.densityDpi;
        tvMyDensity.setText(String.valueOf(dpi));

    }
}



<?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"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="My device info"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:textStyle="bold"/>
    <TextView
        android:id="@+id/mylink"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="android-er.blogspot.com"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/title" />
    <TextView
        android:id="@+id/myArchitecture"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Architecture"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/mylink"
        android:gravity="left"
        android:textSize="30dp"/>
    <TextView
        android:id="@+id/myRelease"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Release"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/myArchitecture"
        android:gravity="left"
        android:textSize="30dp"/>
    <TextView
        android:id="@+id/myDensity"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Density"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/myRelease"
        android:gravity="left"
        android:textSize="30dp"/>

</android.support.constraint.ConstraintLayout>

Wednesday, January 30, 2019

Install Linux Mint 19.1 Tessa - Xfce (64-bit) on VirtuaBox 6/Windows 10

To download Linux Mint, visit https://linuxmint.com/download.php. The current release is 19.1.

This video show steps to download and install Linux Mint 19.1 Tessa - Xfce (64-bit) on Windows 10 with VirtualBox 6.

And then, you are suggested to install Guest Additions, for better performance and functions.



may be interested:
Install OpenJDK on Linux Mint/Ubuntu
Install JetBrains Toolbox App on Linux, and also Android Studio and IntelliJ IDEA (Java IDE)



Tuesday, January 22, 2019

Google + Wikipedia

Announced on 22 January 2019,
Wikimedia Foundation is partnering with Google on a set of initiatives to support a shared commitment of making information more accessible to more people around the world.

Through these partnerships, Google and Wikimedia will be working together to create new and expanded programs to empower editors to create local language content on Wikipedia, as well as developing improved translation tools. To strengthen and support Wikipedia and its mission for generations to come, Google.org will also be contributing $1.1 million to the Wikimedia Foundation and $2 million to the Wikimedia Endowment

Source: Google and Wikimedia Foundation partner to increase knowledge equity online

Monday, January 14, 2019

What is 5G?

What is 5G? | CNBC Explains



Everything You Need to Know About 5G


5G in 2019: The benefits, rollout and challenges at CES 2019

Stable release of Android Studio 3.3 released

Android Studio 3.3 released, with Navigation editor, support Instant Apps in App bundle, as well as build system updates such as lazy task configuration, better debug info when using obsolete APIs, improved incremental Java compilation when using annotation processors, and a preview of the new R8 code shrinker. Also added more granularity in the profiler options and added slow frame highlighting to help debug quicker.

You can download it today from https://developer.android.com/studio/.

Or, if you already installed previous release of Android Studio,  you can simply update to the latest version.

What’s new in Android Studio 3.3

~ Android Developers Blog post Android Studio 3.3


Tuesday, January 1, 2019

Mix using of ImageDecoder and ObjectAnimator

Last posts show how to "Display animated GIF using ImageDecoder" and "Apply PostProcess for ImageDecoder". This example I try to mix using of ImageDecoder and ObjectAnimator, to apply animation on animated GIF.



Modify MainActivity.java
package com.blogspot.android_er.androidimagedecoder;

import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ImageDecoder;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.PostProcessor;
import android.graphics.drawable.AnimatedImageDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageView;
import android.widget.Toast;

import java.io.IOException;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ImageView imageView1 = findViewById(R.id.gifimage1);
        ImageView imageView2 = findViewById(R.id.gifimage2);

        loadGif(imageView1);
        loadRoundGif(imageView2);

        imageView1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                prepareObjectAnimatorRotate((ImageView)v);
            }
        });

        imageView2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                prepareObjectAnimatorAlpha((ImageView)v);
            }
        });
    }

    PostProcessor myPostProcessor =
            new PostProcessor(){
                @Override
                public int onPostProcess(
                        Canvas canvas) {
                    // This will create rounded corners.
                    Path path = new Path();
                    path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
                    int width = canvas.getWidth();
                    int height = canvas.getHeight();
                    path.addRoundRect(0, 0,
                            width, height, 150, 150,
                            Path.Direction.CW);
                    Paint paint = new Paint();
                    paint.setAntiAlias(true);
                    paint.setColor(Color.TRANSPARENT);
                    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
                    canvas.drawPath(path, paint);
                    return PixelFormat.TRANSLUCENT;
                }
            };


    ImageDecoder.OnHeaderDecodedListener myOnHeaderDecodedListener =
            new ImageDecoder.OnHeaderDecodedListener(){
                @Override
                public void onHeaderDecoded
                        (ImageDecoder decoder,
                         ImageDecoder.ImageInfo info,
                         ImageDecoder.Source source) {
                    decoder.setPostProcessor(myPostProcessor);
                }
            };

    private void loadGif(ImageView iv){

        try {
            ImageDecoder.Source source =
                    ImageDecoder.createSource(getResources(), R.drawable.android_er);

            Drawable drawable = ImageDecoder.decodeDrawable(source);

            iv.setImageDrawable(drawable);

            if (drawable instanceof AnimatedImageDrawable) {
                ((AnimatedImageDrawable) drawable).start();
                Toast.makeText(getApplicationContext(),
                        "loadGif: Animation started",
                        Toast.LENGTH_LONG).show();
            }

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

    }

    private void loadRoundGif(ImageView iv){

        try {
            ImageDecoder.Source source =
                    ImageDecoder.createSource(getResources(), R.drawable.android_er);

            //Drawable drawable = ImageDecoder.decodeDrawable(source);
            Drawable drawable = ImageDecoder.decodeDrawable(source,
                    myOnHeaderDecodedListener);

            iv.setImageDrawable(drawable);

            if (drawable instanceof AnimatedImageDrawable) {
                ((AnimatedImageDrawable) drawable).start();
                Toast.makeText(getApplicationContext(),
                        "loadRoundGif: Animation started",
                        Toast.LENGTH_LONG).show();
            }

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

    }

    private void prepareObjectAnimatorRotate(ImageView image){
        TimeInterpolator timeInterpolator =
                new AccelerateDecelerateInterpolator();
        float propertyStart = 0f;
        float propertyEnd = 360f;
        String propertyName = "rotation";
        ObjectAnimator objectAnimator
                = ObjectAnimator.ofFloat(
                        image, propertyName, propertyStart, propertyEnd);
        objectAnimator.setDuration(5000);
        objectAnimator.setRepeatCount(1);
        objectAnimator.setRepeatMode(ObjectAnimator.REVERSE);
        objectAnimator.setInterpolator(timeInterpolator);
        objectAnimator.start();
    }

    private void prepareObjectAnimatorAlpha(ImageView image){
        TimeInterpolator timeInterpolator =
                new AccelerateDecelerateInterpolator();
        float propertyStart = 1f;
        float propertyEnd = 0f;
        String propertyName = "alpha";
        ObjectAnimator objectAnimator
                = ObjectAnimator.ofFloat(
                        image, propertyName, propertyStart, propertyEnd);
        objectAnimator.setDuration(5000);
        objectAnimator.setRepeatCount(1);
        objectAnimator.setRepeatMode(ObjectAnimator.REVERSE);
        objectAnimator.setInterpolator(timeInterpolator);
        objectAnimator.start();
    }
}


Keep using the layout in last post "Apply PostProcess for ImageDecoder".

If you target to animated GIF and it cannot shown, try to disable hardwareAccelerated, refer to "Display animated GIF using ImageDecoder".


Related old post:
Interpolator effect on ObjectAnimator