Sunday 31 January 2016

Opening Sandbox file in External apps using Content Provider


SANDBOX is application's private space, this is where you can save all your application specific data safely. (Unless device is ROOTED)

Yes, before we see how to use it, why actually we need a content provider and how can it help us ?

What if you had to download files from an FTP server and save in your private space and open them at later point, for files like Images, music and text you could easily create your own custom in-app viewers.

Problem if  you need to open a .pdf, a word document or an .xls ect. you will depend on external apps, but since the files are saved in your application memory you can't see them in your sdcard or can't browse them in the external viewer apps.

Solution to this problem is CONTENT PROVIDER, yes!! This allows you to share your private files with external apps so that you can preview / edit based on the permission you define.

Below is a quick code snippet of how it can be implemented :

Create a java class : MyContentProvider.java


public class MyContentProvider extends ContentProvider {     private static final String CLASS_NAME = your defined name;     // The authority is the symbolic name for the provider class     public static final String AUTHORITY = your defined name;     // UriMatcher used to match against incoming requests     private UriMatcher uriMatcher;     @Override     public boolean onCreate() {         uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);         // Add a URI to the matcher which will match against the form         // 'content://com.ashray.example.activity.contentprovider.provider/*'         // and return 1 in the case that the incoming Uri matches this pattern         uriMatcher.addURI(AUTHORITY, "*", 1);         return true;     }     @Override     public ParcelFileDescriptor openFile(Uri uri, String mode)             throws FileNotFoundException {         String LOG_TAG = CLASS_NAME + " - openFile";         Log.v(LOG_TAG,  "Called with uri: '" + uri + "'." + uri.getLastPathSegment());         // Check incoming Uri against the matcher         switch (uriMatcher.match(uri)) {           // If it returns 1 - then it matches the Uri defined in onCreate         case 1:         String fileLocation = "";             // The desired file name is specified by the last segment of the path             // E.g. 'content://com.ashray.example.activity.contentprovider/Abc.txt'             // Take this and build the path to the file         Preference preferences = Preferences.getInstance(YourActivity.getBaseContext());         fileLocation = directorypath +''/"+ uri.getLastPathSegment();         }             // Create & return a ParcelFileDescriptor pointing to the file             // Note: Here we use Read-Write but we can restrict it to Read-Only             ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(                     fileLocation), ParcelFileDescriptor.MODE_READ_WRITE);                       return pfd;             // Otherwise unrecognized Uri         default:             Log.v(LOG_TAG, "Unsupported uri: '" + uri + "'.");             throw new FileNotFoundException("Unsupported uri: "                     + uri.toString());         }     }     // //////////////////////////////////////////////////////////////     // Below methods are not used.     // //////////////////////////////////////////////////////////////     @Override     public int update(Uri uri, ContentValues contentvalues, String s,             String[] as) {         return 0;     }     @Override     public int delete(Uri uri, String s, String[] as) {         return 0;     }     @Override     public Uri insert(Uri uri, ContentValues contentvalues) {         return null;     }     @Override     public String getType(Uri uri) {         return null;     }     @Override     public Cursor query(Uri uri, String[] projection, String s, String[] as1,             String s1) {         return null;     } }

In Activity call the Intent to open the file in external app : The content provider will handle creating a ParcelFileDescriptor pointing to the file, creating a bridge for external app to access the file.

// Eg : To open a Powerpoint file

The below code will either open the file directly in a app which can handle powerpoint files - If only one app is installed in device which can read ppt files.

OR

Show user a list of apps t choose from if multiple apps capable of handling power-point  are installed
in the app


String localFile = path of file to open.

Intent intent = new Intent(Intent.ACTION_VIEW);

intent.setDataAndType(Uri.fromFile(localFile), "application/vnd.ms-powerpoint");

startActivity(intent);


Finally in Manifest file declare the provider, inside the application tag

<provider
            android:name="com.ashray.example.contentprovider.MyContentProvider"
            android:authorities="com.ashray.example.contentprovider.provider"
            android:grantUriPermissions="true"
            android:exported="true" />

Permissions :

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

Friday 22 January 2016

Dynamically Update Color of SeekBar

Hola Androidians!!

Have you ever wanted to design a seek bar which could update its color dynamically when you drag it??

Well I had done this some time back hope this helps :

In your layout.xml file declare the seekbar as below :

 <SeekBar  
         android:id="@+id/settings_seekbar_usage_stogare"  
         android:layout_width="match_parent"  
         android:layout_height="wrap_content"  
         android:progressDrawable="@drawable/seek_bar_bg"  
         android:thumb="@drawable/settings_seekbar_circle"  
         android:thumbOffset="20dp"  
         android:secondaryProgress="0" />  

seek_bar_bg.xml

 <?xml version="1.0" encoding="utf-8"?>  
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >  
   <item android:id="@android:id/background">  
     <shape android:shape="rectangle" >  
       <corners android:radius="5dp" />  
       <gradient  
         android:angle="270"  
         android:endColor="#FFFFFF"  
         android:startColor="#FFFFFF" />  
     </shape>  
   </item>  
   <item android:id="@+id/progressshape">  
     <clip>  
       <shape android:shape="rectangle" >  
         <corners android:radius="5dp" />  
         <gradient  
           android:angle="270"  
           android:endColor="#00ff00"  
           android:startColor="#00ff00" />  
       </shape>  
     </clip>  
   </item>  
 </layer-list>  

Progress Drawable : seek_bar_bg.png    ---->     


Finally, In your Fragment / Activity use the below code in onProgressChanged event of seekbar :

 @Override  
      public void onProgressChanged(SeekBar seekBar, int progress,  
                boolean fromUser) {  
           if(progress > 0)  
                seekbarProgressColor = progress / seekbarProgressValue;  
           System.out.println(seekbarProgressColor);  
           if(seekbarProgressColor <= 50){  
          setProgressBarColor(mSeekBarStorageLimit, Color.rgb( 255 - (255/100 * (100 - (int)(seekbarProgressColor* 2))), 255, 0));  
         }else{  
              setProgressBarColor(mSeekBarStorageLimit, Color.rgb( 255, 255 - (255/100 * (int)((seekbarProgressColor - 50)*2)), 0));  
         }  
      }  
 //Function responsible to change the color of seekbar  
 public void setProgressBarColor(SeekBar seakBar, int newColor){  
          LayerDrawable ld = (LayerDrawable) seakBar.getProgressDrawable();  
          ClipDrawable d1 = (ClipDrawable) ld.findDrawableByLayerId(R.id.progressshape);  
          d1.setColorFilter(newColor, PorterDuff.Mode.SRC_IN);  
        }  

DONE!! Enjoy :-)