Check Google Play service availability

private boolean checkPlayServices() {
        // check google play service availability and make it available
        GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
        int result = googleAPI.isGooglePlayServicesAvailable(this);
        if (result != ConnectionResult.SUCCESS) {
            if (googleAPI.isUserResolvableError(result)) {
                googleAPI.getErrorDialog(this, result,
                        PLAY_SERVICES_RESOLUTION_REQUEST).show();

                //googleAPI.makeGooglePlayServicesAvailable(this);
            }

            return false;
        }

        return true;
    }

References
https://stackoverflow.com/questions/31016722/googleplayservicesutil-vs-googleapiavailability
https://developers.google.com/android/reference/com/google/android/gms/common/GoogleApiAvailability
https://developers.google.com/android/reference/com/google/android/gms/common/ConnectionResult

Saving Files on Android

Obtain Permissions for External Storage

<manifest ...>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>
<manifest ...>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    ...
</manifest>

Save a File on Internal Storage
getFilesDir()
getCacheDir()

File file = new File(context.getFilesDir(), filename);
String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;

try {
  outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
  outputStream.write(string.getBytes());
  outputStream.close();
} catch (Exception e) {
  e.printStackTrace();
}
public File getTempFile(Context context, String url) {
    File file;
    try {
        String fileName = Uri.parse(url).getLastPathSegment();
        file = File.createTempFile(fileName, null, context.getCacheDir());
    } catch (IOException e) {
        // Error while creating file
    }
    return file;
}

Save a File on External Storage

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}
public File getAlbumStorageDir(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()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}
public File getAlbumStorageDir(Context context, String albumName) {
    // Get the directory for the app's private pictures directory.
    File file = new File(context.getExternalFilesDir(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

Delete a File

myFile.delete();
myContext.deleteFile(fileName);

Query Free Space
getFreeSpace()
getTotalSpace()

References
https://developer.android.com/training/basics/data-storage/files.html

Install .apk files Programmatically

 

    private void download() {
        try {

            if (updateInfo == null) {
                dismiss();
                return;
            }

            String fileUrl = updateInfo.baseUrl + updateInfo.file;
            URL url = new URL(fileUrl);

            URLConnection conection = url.openConnection();
            conection.connect();

            // getting file length
            int lenghtOfFile = conection.getContentLength();

            // in kb
            final int fLengthOfFile = lenghtOfFile / 1000;

            // initialize progressbar
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    progressBarUpdate.setProgress(0);
                    String progress = 0 + "%";
                    textViewProgressPercent.setText(progress);
                    String bStr = String.format(Locale.US, "%d/%d", 0, fLengthOfFile);
                    textViewProgressBytes.setText(bStr);
                }
            });

            // input stream to read file - with 8k buffer
            InputStream input = new BufferedInputStream(url.openStream(), 8192);

            File folder = getContext().getFilesDir();

            String path = folder.getAbsolutePath() + "/" + updateInfo.file;
            File saveFile = new File(path);

            saveFile.createNewFile();

            // Output stream to write file
            OutputStream output = new FileOutputStream(saveFile, false);

            byte data[] = new byte[1024];

            int total = 0;
            int count = 0;

            while ((count = input.read(data)) != -1) {

                if (cancelCalled) {
                    dismiss();
                    return;
                }

                total += count;

                final int progressPercent = (int) ((total * 100) / lenghtOfFile);
                final int fTotal = total / 1000;


                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        progressBarUpdate.setProgress(progressPercent);
                        String progress = progressPercent + "%";
                        textViewProgressPercent.setText(progress);
                        String bStr = String.format(Locale.US, "%d/%d", fTotal, fLengthOfFile);
                        textViewProgressBytes.setText(bStr);
                    }
                });

                // writing data to file
                output.write(data, 0, count);
            }

            // flushing output
            output.flush();

            // closing streams
            output.close();
            input.close();

            saveFile = new File(path);

            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
                saveFile.setReadable(true, false);
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.setDataAndType(Uri.fromFile(saveFile), "application/vnd.android.package-archive");
                getContext().getApplicationContext().startActivity(intent);
            } else {
                Intent intent = new Intent(Intent.ACTION_VIEW);
                Uri fileUri = FileProvider.getUriForFile(getContext(),
                        "ir.mhdr.provider",
                        saveFile);

                intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
                intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                startActivity(intent);
            }


            dismiss();

        } catch (Exception e) {
            e.printStackTrace();
            //FirebaseCrash.report(e);
            dismiss();
        }
    }

AndroidManifest.xml

        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="ir.mhdr.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="bmi.apk" path="" />
</paths>

the reason that my path is empty is according to google documents :

<files-path name="name" path="path" />

Represents files in the files/ subdirectory of your app’s internal storage area. This subdirectory is the same as the value returned by Context.getFilesDir() and because the path is relative so while my file is stored in the root directory of getFilesDir() the path should be empty.

References
https://developer.android.com/reference/android/support/v4/content/FileProvider.html
https://stackoverflow.com/questions/4967669/android-install-apk-programmatically
https://stackoverflow.com/questions/3568142/android-how-to-open-an-apk-file-after-downloading-for-auto-update
https://stackoverflow.com/questions/38200282/android-os-fileuriexposedexception-file-storage-emulated-0-test-txt-exposed

Read XML from URL in Android

Read XML file :

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new URL(url).openStream());

Parse :

File fXmlFile = new File("/Users/mkyong/staff.xml");
	DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
	DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
	Document doc = dBuilder.parse(fXmlFile);

	//optional, but recommended
	//read this - http://stackoverflow.com/questions/13786607/normalization-in-dom-parsing-with-java-how-does-it-work
	doc.getDocumentElement().normalize();

	System.out.println("Root element :" + doc.getDocumentElement().getNodeName());

	NodeList nList = doc.getElementsByTagName("staff");

	System.out.println("----------------------------");

	for (int temp = 0; temp < nList.getLength(); temp++) {

		Node nNode = nList.item(temp);

		System.out.println("\nCurrent Element :" + nNode.getNodeName());

		if (nNode.getNodeType() == Node.ELEMENT_NODE) {

			Element eElement = (Element) nNode;

			System.out.println("Staff id : " + eElement.getAttribute("id"));
			System.out.println("First Name : " + eElement.getElementsByTagName("firstname").item(0).getTextContent());
			System.out.println("Last Name : " + eElement.getElementsByTagName("lastname").item(0).getTextContent());
			System.out.println("Nick Name : " + eElement.getElementsByTagName("nickname").item(0).getTextContent());
			System.out.println("Salary : " + eElement.getElementsByTagName("salary").item(0).getTextContent());

		}

References
https://stackoverflow.com/questions/16958081/java-how-to-read-xml-from-url
https://www.mkyong.com/java/how-to-read-xml-file-in-java-dom-parser/

Prevent locale changes on Android application

    public class MyApplication extends Application {

    @Override
    protected void attachBaseContext(Context base) {
        Resources res = base.getResources();

        Locale locale = new Locale("en");
        Locale.setDefault(locale);

        Configuration config = new Configuration();
        config.locale = locale;

        res.updateConfiguration(config, res.getDisplayMetrics());

        super.attachBaseContext(base);
    }
}

Support layout mirroring

<manifest>
    <application
        .
        .
        .
        android:supportsRtl="false"
        tools:replace="android:supportsRtl"
        >
    </application>
</manifest>

 

References
https://stackoverflow.com/questions/37894163/is-there-a-android-attribute-to-disable-locale-change-in-my-app/
https://stackoverflow.com/questions/11013904/disable-localization-in-android-application
https://stackoverflow.com/questions/26450489/disable-automatic-layout-change-on-android