Sunday, May 26, 2019

Android PDF Write / Read using Android 9 (API level 28)

Android 9 (API level 28) introduces great new features and capabilities for users and developers. Some of the changes impacts File Write and Read. The following is a solution to the File Write / Read problem for pdf files

Code Structure 




GenericFileProvider.java 

package com.zackdawood;

import android.support.v4.content.FileProvider;

public class GenericFileProvider extends FileProvider {
}

FileDownloader.java
package com.zackdawood;

import android.util.Log;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class FileDownloader {

    private static final String TAG = "FileDownloader";

    private static final int MEGABYTE = 1024 * 1024;

    public static void downloadFile(String fileUrl, File directory) {
        try {
            Log.v(TAG, "downloadFile() invoked ");
            Log.v(TAG, "downloadFile() fileUrl " + fileUrl);
            Log.v(TAG, "downloadFile() directory " + directory);

            URL url = new URL(fileUrl);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.connect();

            InputStream inputStream = urlConnection.getInputStream();
            FileOutputStream fileOutputStream = new FileOutputStream(directory);
            int totalSize = urlConnection.getContentLength();

            byte[] buffer = new byte[MEGABYTE];
            int bufferLength = 0;
            while ((bufferLength = inputStream.read(buffer)) > 0) {
                fileOutputStream.write(buffer, 0, bufferLength);
            }
            fileOutputStream.close();
            Log.v(TAG, "downloadFile() completed ");

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Log.e(TAG, "downloadFile() error" + e.getMessage());
            Log.e(TAG, "downloadFile() error" + e.getStackTrace());
        } catch (MalformedURLException e) {
            e.printStackTrace();
            Log.e(TAG, "downloadFile() error" + e.getMessage());
            Log.e(TAG, "downloadFile() error" + e.getStackTrace());
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "downloadFile() error" + e.getMessage());
            Log.e(TAG, "downloadFile() error" + e.getStackTrace());
        }
    }
}
MainActivity.java
package com.zackdawood;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private static final String[] PERMISSIONS = {android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE};


    private static boolean hasPermissions(Context context, String... permissions) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) {
            for (String permission : permissions) {
                if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                    return false;
                }
            }
        }
        return true;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.v(TAG, "onCreate() Method invoked ");

        ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS, 112);

    }

    public void request(View view) {

        ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS, 112);

    }

    public void view(View view) {
        Log.v(TAG, "view() Method invoked ");

        if (!hasPermissions(MainActivity.this, PERMISSIONS)) {

            Log.v(TAG, "download() Method DON'T HAVE PERMISSIONS ");

            Toast t = Toast.makeText(getApplicationContext(), "You don't have read access !", Toast.LENGTH_LONG);
            t.show();

        } else {
            File d = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);  // -> filename = maven.pdf
            File pdfFile = new File(d, "maven.pdf");

            Log.v(TAG, "view() Method pdfFile " + pdfFile.getAbsolutePath());

            Uri path = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileprovider", pdfFile);


            Log.v(TAG, "view() Method path " + path);

            Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
            pdfIntent.setDataAndType(path, "application/pdf");
            pdfIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            pdfIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

            try {
                startActivity(pdfIntent);
            } catch (ActivityNotFoundException e) {
                Toast.makeText(MainActivity.this, "No Application available to view PDF", Toast.LENGTH_SHORT).show();
            }
        }
        Log.v(TAG, "view() Method completed ");

    }

    public void download(View view) {
        Log.v(TAG, "download() Method invoked ");

        if (!hasPermissions(MainActivity.this, PERMISSIONS)) {

            Log.v(TAG, "download() Method DON'T HAVE PERMISSIONS ");

            Toast t = Toast.makeText(getApplicationContext(), "You don't have write access !", Toast.LENGTH_LONG);
            t.show();

        } else {
            Log.v(TAG, "download() Method HAVE PERMISSIONS ");

            //new DownloadFile().execute("http://maven.apache.org/maven-1.x/maven.pdf", "maven.pdf");
            new DownloadFile().execute("http://www.axmag.com/download/pdfurl-guide.pdf", "maven.pdf");

        }

        Log.v(TAG, "download() Method completed ");

    }

    private class DownloadFile extends AsyncTask<String, Void, Void> {

        @Override
        protected Void doInBackground(String... strings) {
            Log.v(TAG, "doInBackground() Method invoked ");

            String fileUrl = strings[0];   // -> http://maven.apache.org/maven-1.x/maven.pdf
            String fileName = strings[1];  // -> maven.pdf
            String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
            File folder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);

            File pdfFile = new File(folder, fileName);
            Log.v(TAG, "doInBackground() pdfFile invoked " + pdfFile.getAbsolutePath());
            Log.v(TAG, "doInBackground() pdfFile invoked " + pdfFile.getAbsoluteFile());

            try {
                pdfFile.createNewFile();
                Log.v(TAG, "doInBackground() file created" + pdfFile);

            } catch (IOException e) {
                e.printStackTrace();
                Log.e(TAG, "doInBackground() error" + e.getMessage());
                Log.e(TAG, "doInBackground() error" + e.getStackTrace());


            }
            FileDownloader.downloadFile(fileUrl, pdfFile);
            Log.v(TAG, "doInBackground() file download completed");

            return null;
        }
    }
}
AndroidManifest.xml

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

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


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

    <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"
        android:networkSecurityConfig="@xml/network_security_config">
        <provider
            android:name=".GenericFileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/external_files"/>
        </provider>
        <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>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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">

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

        <Button
            android:id="@+id/button3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="200px"
            android:onClick="download"
            android:text="@string/file_download" />


        <Button
            android:id="@+id/button4"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="200px"
            android:onClick="view"
            android:text="@string/file_view" />

        <Button
            android:id="@+id/button5"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="200px"
            android:onClick="request"
            android:text="@string/file_request" />
    </LinearLayout>


</android.support.design.widget.CoordinatorLayout>
strings.xml
<resources>
    <string name="app_name">DemoInternalDownload</string>
    <string name="action_settings">Settings</string>
    <string name="file_view">File View</string>
    <string name="file_download">File Download</string>
    <string name="file_request">Request Access Again</string>

</resources>
external_files.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>
network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">maven.apache.org</domain>
        <domain includeSubdomains="true">www.axmag.com</domain>
    </domain-config>
</network-security-config>
build.gradle
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.zackdawood"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
Prompt Screen
Output Screen

Sunday, January 20, 2019

Mac OS Compress PDF with adjustable ratio & Size

ColorSync Utility is what your looking for. For me the standard compression was also too little resolution & too lossy compression. So I created a new filter in ColorSync - which then becomes available in e.g. Preview: Resolution 200 dpi, jpeg quality ~75%
Step 1: Open ColorSync Utility & create the new filter such as below
Screenshot: New ColorSync filter

The above settings give me files with acceptable size and decent quality (e.g. for sending by e-mail)
Step 2: Open the PDF in Preview, then choose File > Export, Click the Quartz Filter pop-up menu, then choose the relevant filter ("Reduce File Size 200dpi" in this case)
Apple Preview, export PDF

Sunday, December 16, 2018

JavaScript Mutable and Immutable Objects



In JavaScript Primitives are immutable, which means that the value is passed instead of reference.
For Objects the reference is passed instead of value. Example as below,

//Primitives are immutable
var a = 10;
var b = a;

console.log("a: "+a);
console.log("b: "+b);

a =20;

console.log("a: "+a);
console.log("b: "+b);

//Mutable
var c = {name: "Zack"};

var d = c;
console.log("c: "+c.name);
console.log("d: "+d.name);
d.name = "Arnold";
console.log("c: "+c.name);
console.log("d: "+d.name);

Ensure whether you are passing value or reference during development. This is one of the basic concepts in JavaScript. 

JavaScript Objects Types


In JavaScript there are 3 ways you can create an Object. Examples as below,

var object1 =
{
    name: "Zack",
    age: 35
}

console.log("Object 1 Name: "+object1.name);

var object2 = new Object();
object2.name = "Zack";
object2.age = 35;

console.log("Object 2 Name: "+object2.name);

function Object3(name, age)
{
    this.name = name;
    this.age = age;
    this.getName =function () {
        return this.name;
    }
}
var object3 = new Object3("Zack", 35)
console.log("Object 3 Name: "+object3.getName());

object1.sex = "male";
object2.sex = "male";
Object3.sex = "male";// Value will be undefined for the Object
//Object3.prototype.sex = "male";

console.log("Object 1: "+ object1.sex);
console.log("Object 2: "+ object2.sex);
console.log("Object 3: "+ object3.sex);

The 3rd Type of Object is the most used type, since it is highly reusable. 

Tuesday, October 2, 2018


When installing Atom Packages some machine will receive a error as

failed: unable to get local issuer certificate (UNABLE_TO_GET_ISSUER_CERT_LOCALLY)

PS C:\Code\NodeJS Exercise> apm install split-diff
Installing split-diff to C:\Users\zack.dawood\.atom\packages failedRequest for package information failed: unable to get local issuer certificate (UNABLE_TO_GET_ISSUER_CERT_LOCALLY)



In order to fix this execute the following command

apm config set strict-ssl false

Now install the required package, it should work

apm install split-diff 


Sunday, February 19, 2017

VMWare Fusion Mac Power Maps Error Fix



VMWare Fusion Mac Power Maps Error Fix 

If you are using VMWare Fusion 7-8.5 and Running Window 10. When you use Power Maps / 3D Maps Features in Microsoft Office Excel 2013 / 2016 you will have a error as below,

---------------------------
3D Maps
---------------------------
Cannot initialize DirectX. Confirm that your hardware supports DirectX 10 or later and that you have the latest video card driver installed.
---------------------------
OK   
---------------------------




To Fix the problem Shut Down the Windows 10 Virtual Machine, Click the Settings and Select Display



Check the Accelerate 3D Graphics Settings




UnCheck the Accelerate 3D Graphics Settings



Start the Virtual Machine, Open the Excel, Insert, 3D Maps


Friday, July 3, 2015

Do It Yourself ToastMasters Timing Light

Do It Yourself ToastMasters Timing Light 

Green, Amber (Yellow), Red signals are commonly used in Toastmasters clubs to show speakers when they have reached minimum time, are halfway through their allotted time, and when they have reached maximum time. Many clubs use a set of colored cards–some Toastmasters even carry small colored cards in their wallets for impromptu Toastmasters meetings!
But cards have to be held up in the air and are not very eye-catching. Timing lights are preferred, where actual green, amber and red lights can be turned on and get the speaker’s attention. The official Toastmasters Signal Light costs $110 to $185 depends on the area you live in.


Toastmasters Signal Light costs $110 to $185

Toastmasters Signal Light costs $110 to $185

I wanted the same in battery operated without external power and for low cost. There are other do it yourself kits but that needs external power, hence i have decided to make my own. DO IT YOURSELF. 

Do It Yourself ToastMasters Timing Light 

I managed to do it yourself toastmasters timing light with less $50 including batteries












Parts: 

I live in Ontario, Canada. Bought it from A1 Electronics
http://www.a1parts.com/led/led.htm
http://www.a1parts.com/battery_holders/battery_holders.htm
http://www.a1parts.com/switches/index.html#ROTARY SWITCHES

1. Signal Light 30 LED`s - $7.50 x 3 = $22.50
2. Battery Holder - $2.80
3. Rotary Switch - $4.80
4. Incandescent indicators 12VDC - $2.50 x 3 = $7.50
5. Rotary Switch Knob - $0.99
6. Dollarama Wooden Box (Transparent Lid) - $2.00

Total Parts = $40.59


1. Signal Light 30 LED`s





Part Number MCD
DK4555-G  (Green) 18000
DK4555-Y  (Yellow) 7500
DK4555-R  (Red) 6500

12V  $7.50 / each

2. Battery Holder 



Part Number: 4200A
 Um3x8 for Eight "AA" Cells
Size: 60mm (L) x 29mm (W)x58mm (H)
$2.80


3. Rotary Switch


ITEM NO. DK6561 C
SECTIONS: 1
POLES: 3
POSTIONS: 4 (OFF, GREEN, YELLOW, RED)
$4.80

4. Incandescent indicators 12VDC




Incandescent indicators 12VDC

55-492(Red Lens)
55-493(Amber Lens)
55-495(Green Lens)

$2.50


5. Rotary Switch Knob





Part Number
54-374-BL
A mm -
B mm - 30
C mm - 15
Shaft mm - 6.35

Price - $0.99


6. Dollarama Wooden Box (Transparent Lid)




$2.00 Dollarama

7. Tools 


Hook - up Wires  (Stranded) (If you don't have $3)

Soldering Iron (If you don't have one you can get it for $5)



8 AA Batteries