Thursday 31 December 2015

What are Normal permissions in Android?

There are two types of permissions:-

1. Normal permissions 
2. Runtime Permissions

We are familiar with Runtime permissions, here we will be discussing about Normal Permissions.
Normal permissions are the permissions which are automatically granted during install time. We need not to check these in our code(i.e runtime).And these are the permissions which user can not revoke from app settings as well.
We simply declare these permissions in the Android Manifest.xml and it will work nomally as did earlier.
.
Below is the list of permissions :-

android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.READ_SYNC_SETTINGS
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER

Sunday 6 December 2015

Download/Upload files using Dropbox Api Android

This tutorial is about Downloading/Uploading files from/to Dropbox using DropboxApi Android.


Firstly create your App key and App Secret key to use this api from below link.
Dropbox App Console : https://www.dropbox.com/developers-v1/apps

Include the below jars files from the downloaded Dropbox Sdk :
1. dropbox-android-sdk-1.6.3.jar
2. json_simple-1.1.jar

1. MainActivity.java

public class MainActivity extends AppCompatActivity {

        //path of the file to be uploaded here    
String path= Environment.getExternalStorageDirectory()
            .getAbsolutePath() + "/photo.jpg";
    final static private String APP_KEY = "";
    final static private String APP_SECRET = "";
    private DropboxAPI<AndroidAuthSession> mDBApi;
    DropboxAPI.Entry response;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /**
         *   i am using this mode . you can use the Async task to upload and download file
         */
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
        setContentView(R.layout.activity_main);
        //Generate dropbox session from the generated keys
        AppKeyPair appKeys = new AppKeyPair(APP_KEY, APP_SECRET);
        AndroidAuthSession session = new AndroidAuthSession(appKeys);
        mDBApi = new DropboxAPI<AndroidAuthSession>(session);
        //Check if user has already authorized the dropbox app for you..
        if(!getAccessToken().equalsIgnoreCase("")){
            mDBApi.getSession().setOAuth2AccessToken(getAccessToken());
        }else{
            //if not authorized. i.e for the first time then
            mDBApi = new DropboxAPI<AndroidAuthSession>(session);
            mDBApi.getSession().startOAuth2Authentication(MainActivity.this);
        }

        ((Button) findViewById(R.id.uploaddata)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                uploadFile(path);
            }
        });

        ((Button) findViewById(R.id.downloadfile)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                downloadFile(Environment.getExternalStorageDirectory()
                        .getAbsolutePath());
            }
        });
    }

    protected void onResume() {
        super.onResume();
        //if first time and save the Access Token here
        if(getAccessToken().equalsIgnoreCase("")) {
            if (mDBApi.getSession().authenticationSuccessful()) {
                try {
                    // Required to complete auth, sets the access token on the session
                    mDBApi.getSession().finishAuthentication();
                    String accessToken = mDBApi.getSession().getOAuth2AccessToken();
                    saveAccessToken(accessToken);
                } catch (IllegalStateException e) {
                    Log.i("Error", "Error authenticating", e);
                }
            }
        }
    }

    private void saveAccessToken(String accessToken){
        SharedPreferences sharedPreferences=getSharedPreferences("Prefs", Context.MODE_PRIVATE);
        sharedPreferences.edit().putString("accessToken", accessToken).commit();
    }

    private String getAccessToken(){
        SharedPreferences sharedPreferences=getSharedPreferences("Prefs", Context.MODE_PRIVATE);
        return sharedPreferences.getString("accessToken","");
    }

    public void uploadFile(String file_path) {
        File file = new File(file_path);
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
        } catch (FileNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        try {
            response = mDBApi.putFile("/photo.jpg", inputStream,
                    file.length(), null, null);
            if(response.rev!=null){
                Toast.makeText(this,"File Uploaded successfully..",Toast.LENGTH_LONG).show();
            }
            Log.i("Success", "The uploaded file's rev is: " + response.rev);
        } catch (DropboxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void downloadFile(String file_path) {
       //Path where you want to stored the downloaded file form dropbox
        File file = new File(file_path+"/testphoto.jpg");
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        DropboxAPI.DropboxFileInfo info = null;
        try {
            info = mDBApi.getFile("/photo.jpg", null, outputStream, null);
            if(info.getMetadata().rev!=null){
                Toast.makeText(this,"File Downloaded successfully..",Toast.LENGTH_LONG).show();
            }
            Log.i("Success", "The file's rev is: "
                    + info.getMetadata().rev);
        } catch (DropboxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

2. Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.kamal.dropboxdemoapi" >
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name="com.dropbox.client2.android.AuthActivity"
            android:launchMode="singleTask"
            android:configChanges="orientation|keyboard">
            <intent-filter>
                <!-- Change this to be db- followed by your app key -->
                <data android:scheme="db-Your App key here" />
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.BROWSABLE"/>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>


Find the source from  Github : https://github.com/CammyKamal/BlogTutorials/tree/master/DropBoxDemoApi

Friday 4 December 2015

Handling GCM Push Notifications in Android Flavors

In Android Flavors generally we have different package names in our single app for flavours.

When implementing GCM Push Notifications in our android app in case of Flavors there is very little thing that we need to do differently.

Since our Package Name i.e application id is going to be different for different Flavors then push notifications going to be a problem in that case.

Below is the permissions that we generally declare in manifest file when using GCM.
   

 <!-- GCM requires a Google account. -->
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />

    <!-- Creates a custom permission so only this app can receive its messages. -->
    <permission
        android:name="yourpackagename.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />

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

    <!-- This app has permission to register and receive data message. -->
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
   
   
    Now suppose if we are implementing flavours then way of defining these permissions will change.
    Suppose we have below flavours in our build.gradle.
   
    productFlavors {
                        paid
                    {
                        applicationId "com.example.paid"
                        versionCode 1
                        versionName "1.0"
                    }
                        free
                    {
                        applicationId "com.example.free"
                        versionCode 1
                        versionName "1.0"
                    }
                }
               
           
Now when running GCM according to different variants will be a problem. GCM will work accordingly whose permission with package name is defined in manifest.

So add runtime Package Name to the manifest permissions in case of Android Flavors. Below is how can we declare single permissions for multiple Android Flavors in android manifest file.
   
   

    <!-- GCM notifications permissions-->


    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

    

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

    

    <permission android:name="${applicationId}.permission.C2D_MESSAGE"

        android:protectionLevel="signature" />

    

    <uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />

    
   
Here ${applicationId} will be replaced by the applicationId of the running build variant defined in build.gradle of the app.


Cheers!!

Thursday 3 December 2015

Snackbar to show Internet Connectivity Changes in App


Here Snackbar will be shown everytime when internet connection is available or connection lost for user via broadcast receiver.

Snackbar works from api 8 and above so its a cool thing to implement for showing such short messages.

 You need to extend your activity with AppCompatActivity for Snackbar.

Add below dependency in your build.gradle compile 'com.android.support:design:22.2.1'

 1. MainActivity.java

public class MainActivity extends AppCompatActivity {
    public static int TYPE_WIFI = 1;
    public static int TYPE_MOBILE = 2;
    public static int TYPE_NOT_CONNECTED = 0;
    private Snackbar snackbar;
    private CoordinatorLayout coordinatorLayout;
    private boolean internetConnected=true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        coordinatorLayout=(CoordinatorLayout)findViewById(R.id.coordinatorlayout);
    }

    @Override
    protected void onResume() {
        super.onResume();
        registerInternetCheckReceiver();
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(broadcastReceiver);
    }
    /**
     *  Method to register runtime broadcast receiver to show snackbar alert for internet connection..
     */
    private void registerInternetCheckReceiver() {
        IntentFilter internetFilter = new IntentFilter();
        internetFilter.addAction("android.net.wifi.STATE_CHANGE");
        internetFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        registerReceiver(broadcastReceiver, internetFilter);
    }

    /**
     *  Runtime Broadcast receiver inner class to capture internet connectivity events
     */
    public BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String status = getConnectivityStatusString(context);
            setSnackbarMessage(status,false);
        }
    };

    public static int getConnectivityStatus(Context context) {
        ConnectivityManager cm = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        if (null != activeNetwork) {
            if(activeNetwork.getType() == ConnectivityManager.TYPE_WIFI)
                return TYPE_WIFI;

            if(activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE)
                return TYPE_MOBILE;
        }
        return TYPE_NOT_CONNECTED;
    }

    public static String getConnectivityStatusString(Context context) {
        int conn = getConnectivityStatus(context);
        String status = null;
        if (conn == TYPE_WIFI) {
            status = "Wifi enabled";
        } else if (conn == TYPE_MOBILE) {
            status = "Mobile data enabled";
        } else if (conn == TYPE_NOT_CONNECTED) {
            status = "Not connected to Internet";
        }
        return status;
    }
    private void setSnackbarMessage(String status,boolean showBar) {
        String internetStatus="";
        if(status.equalsIgnoreCase("Wifi enabled")||status.equalsIgnoreCase("Mobile data enabled")){
            internetStatus="Internet Connected";
        }else {
            internetStatus="Lost Internet Connection";
        }
        snackbar = Snackbar
                .make(coordinatorLayout, internetStatus, Snackbar.LENGTH_LONG)
                .setAction("X", new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        snackbar.dismiss();
                    }
                });
        // Changing message text color
        snackbar.setActionTextColor(Color.WHITE);
        // Changing action button text color
        View sbView = snackbar.getView();
        TextView textView = (TextView) sbView.findViewById(android.support.design.R.id.snackbar_text);
        textView.setTextColor(Color.WHITE);
        if(internetStatus.equalsIgnoreCase("Lost Internet Connection")){
            if(internetConnected){
                snackbar.show();
                internetConnected=false;
            }
        }else{
            if(!internetConnected){
                internetConnected=true;
                snackbar.show();
            }
        }
    }
}


2. 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"
    android:id="@+id/coordinatorlayout"
    android:fitsSystemWindows="true"
    tools:context="com.example.kamalvaid.internetcheckandsnackbar.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>
 
 
3. Add these permissions to manifest file

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


Github Link https://github.com/CammyKamal/BlogTutorials/tree/master/InternetCheckAndSnackBar

Output: