Category Archives: Education

Static navigation path snapshot from Google Map API

Ever want Uber like snap shot path history in the email? I found a way to perform just that. The method requires to make a REST call to Direction API then use the “overview_polyline -> points” object as query key for the snapshot’s link.

  1. Get browser API key from google developer’s console
  2. You will have to enable 2 Google API
    1. Google Map Direction API
    2. Google Map Javascript API
  3. Make a REST call using Google Map Direction API
    1. Rest call will contain 3 major information as query keys
      1. origin=<lat,lng>
      2. destination=<lat,lng>
      3. key=<browser api key>
    2. Here is an example of the direction call: https://maps.googleapis.com/maps/api/directions/json?origin=37.421020,-122.084197&destination=37.616541,-122.384304&key=<Your API Key>
    3. The response JSON will consist routes[x] ->overview_polyline -> points
  4. Using the newly acquires “points” object, construct the link for the static map snapshot using Google Map Javascript API.
    1. There are few query keys that will be required to display the map accordingly.
      1. size=<width x height>
      2. markers=<markerStyles|markerLocation1| markerLocation2|…>
      3. path=<weight|color|enc:<points object from 1st REST CALL>|….>
      4. key=<browser api key>
    2. The end result of the url format will be similar to this https://maps.googleapis.com/maps/api/staticmap?size=400×400&markers=size:mid|color:green|37.421020,-122.084197&markers=size:mid|color:red|37.616541,-122.384304&path=weight:3|color:blue|enc:<points>&key=<Your API Key>

 

Example Static Image:

Advertisements

Parsing CronJob Expression in Android

I had been trying to parse a cron expression string in my Android app and came across this CronExpression Code source code. I move it into my project and you can just use it off the shelve by calling

CronExpression conExpression = new CronExpression(“* * 10 * * ?”); // This will construct a cronjob which runs at 10am daily.

After obtaining the object, you can explore to more method that it provides for your business logic.

Simulate Slide to Unlock in application

Here I will showcase on how to create a slide to unlock similar to old Android lockscreen. I will customize the seekbar to transparent and replace the generic circle with custom icons. We will need 2 different icons to reflect locked and unlocked state.

First, we need to define the seekbar element in our layout file

<SeekBar
android:id="@+id/seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="0"
android:progressDrawable="@android:color/transparent"
android:thumb="@drawable/ic_lock"/>;

Second, we need to hook up the seekbar that we specified in the layout file in our class

// Hooking up seekbar
SeekBar mSeekbar = (SeekBar) view.findViewById(R.id.seekbar);
// Set listener to our newly created seekbar
mSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

        // Perform your animation of the thumb icon if any, here I will progressively make the thumb icon transparent
        int alpha = (int)(progress * (255/100));
        seekBar.getThumb().setAlpha(255 - alpha);
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        // This will be called when user starts to touch the icon
    }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
               
                // When user lift up the touch, we will check if it is at the end of the bar. If it is not the end, then we will set the progress status to 0 so it jumps back to the origin point
                if (seekBar.getProgress() &lt; 85){
                    seekBar.setThumb(getActivity().getResources().getDrawable(R.drawable.ic_lock));
                    seekBar.setProgress(0);
                } else {
                    // Put all the logic we want to proceed after unlock here
        }
    }
});

android.support.test.espresso.PerformException: Error performing ‘single click’

I encounter the following exception while writing the Espresso test case which involve entering text into edittext component. From what I can tell is the window loses focus and system cant find the next view for action that needs to be process. As a result, after I tell the Espresso framework to enter text, I post a closeKeyboard api to the same edittext so it can be close and Espresso framework able to find the next onView ID.

Error:
android.support.test.espresso.PerformException: Error performing ‘single click’….

Workaround: onView(withId(R.id.edittext_username)).perform(clearText(),typeText(“xxxxx”));
onView(withId(R.id.edittext_username)).perform(closeSoftKeyboard());
Thread.sleep(1000);
//…. next edittext entry

* Please post comments if anyone has a better solution to this.

Creating your own custom dialogfragment

I came accross an error “java.lang.IllegalStateException: Fragment already added:” whenever I try to show my dialogfragment. FindFragmentByTag is not reliable because I do not like to keep track of the dialog and the surprises that sometime it return NULL.

Here is the example of how one can customize the DialogFragment to your own taste. In this class, I define an extra parameter called isDialogShown to make my life easier so I do not have to rely on getFragmentManager().findFragmentByTag() that most of the time will return null object.

To check if the dialog is up, simple just check mDialogFragment.isDialogShown() and call mDiaglogFragment.dismiss() before fragment.show().

Initialize:

MyCustomDialogFragment dialog = new MyCustomDialogFragment(new OnDialogButtonClickListener(){
    
        @Override
        public void onDialogPositiveClick(int status){
          // Do your stuff here
          dialog.dismiss();
        };

        @Override
        public void onDialogNegativeClick(int status){
          // Do your stuff here
          dialog.dismiss();
        };
});

// Set texts that you want to show in your dialog
dialog.setParameters(....);

Showing dialog:


// Always check if dialog is currently shown
if (dialog.isDialogShown(){
   dialog.dismiss();
}

dialog.show(getFragmentManager(), MyCustomDialogFragment.TAG);

MyCustomDialogFragment class:

public class MyCustomDialogFragment extends DialogFragment{

    public static String TAG = MyCustomDialogFragment.class.getSimpleName();

    // Define listener that will be called when positive/negative button is pressed.
    public interface OnDialogButtonClickListener{
        public void onDialogPositiveClick(int status);
        public void onDialogNegativeClick(int status);
    }

    private OnDialogButtonClickListener mListener;

    private boolean isDialogShown = false;

    private String mTitleLabel="", mBodyLabel="", mPositiveLabel="", mNegativeLabel="";

    public MyCustomDialogFragment(OnDialogButtonClickListener listener){
        mListener = listener;
    }

    /**
     * Method to set dialog parameters
     * @param title for dialog
     * @param content for dialog
     * @param positiveLabel for positive button
     * @param negativeLabel for negative button
     */
    public void setParameters(String title, String content, String positiveLabel, String negativeLabel){
        mTitleLabel = title;
        mBodyLabel = content;
        mPositiveLabel = positiveLabel;
        mNegativeLabel = negativeLabel;
    }

    @Override
    public void show(FragmentManager manager, String tag) {
        super.show(manager, tag);
        isDialogShown = true;
    }

    @Override
    public void dismiss() {
        super.dismiss();
        isDialogShown = false;
    }

    public boolean isDialogShown() {return isDialogShown;}

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Use the Builder class for convenient dialog construction
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle(mTitleLabel)
            .setMessage(mBodyLabel)
            .setPositiveButton(mPositiveLabel, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    mListener.onDialogPositiveClick(mStatusCode);
                }
            });

        // Sometime, we do not want to show negative button
        if (!mNegativeLabel.equals("")){
            builder.setNegativeButton(mNegativeLabel, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    mListener.onDialogNegativeClick(mStatusCode);
                }
            });
        }

        // Create the AlertDialog object and return it
        return builder.create();
    }
}

Dynamically load a class based on string in Android

Method to get loaded class. The method will return null if class is not loaded successfully.

public Object getDeviceClass(Context context, String packageName, String className){
  try {
            // Load the dex files for loading the dynamic class
            PackageManager pm = context.getPackageManager();
            File dexOutputDir = context.getDir("dex", Context.MODE_PRIVATE);
            ApplicationInfo ai = pm.getApplicationInfo(context.getPackageName(), 0);
            String sourceApk = ai.publicSourceDir;
            DexClassLoader dexLoader = new DexClassLoader(sourceApk,
                    dexOutputDir.getAbsolutePath(),
                    null,
                    context.getClassLoader());

            // Now load the corresponding class based on the class name
            Class<?> targetClass = Class.forName(packageName + "." + className, true, dexLoader);

            return targetClass.getConstructor().newInstance();

        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

return null
}

If success, you can easily cast it to your corresponding class. The loaded class object needs to extend the parent class.

       Object loadedClass = getDeviceClass(context,packagename,classname);
       ParentClass yourParentClass = (ParentClass)loadedClass;
       yourParentClass.publicMethod();

How to copy a ParseObject to a new ParseObject in different class

There is no function to copy a ParseObject into another class. In order to do so, one will need to create a ParseObject of the new class and re-assign all the keyset into the new ParseObject.

ParseObject is kinda like a Map object, so it is easy to retrieve all available keys, just as what you will do with a map.

ParseObject sourceObject = sourceParseObject;
ParseObject targetObject = new ParseObject("NewClass");
for (Iterator it = sourceObject.keySet().iterator(); it.hasNext();) {
      Object key = it.next();
      targetObject.put(key.toString(),sourceObject.get(key.toString());
    }

Simple method to generate random password

   public static String generateTempPassword(int length){
	   String character = "qwertyuioplkjhgfdsazxcvbnm1234567890POIUYTREWQASDFGHJKLMNBVCXZ!@#$%&";
	   StringBuffer sb = new StringBuffer();
	   while(length>0){
		   double index = Math.random() * character.length();
		   sb.append(character.charAt((int)index));
		   length--;
	   }
	   return sb.toString();
   }

Android MapFragment exception when clicked twice

My application crashed when I re-open the same MapFragment again twice.

E/AndroidRuntime(27409): Caused by: java.lang.IllegalArgumentException: Binary XML file line #5: Duplicate id 0x7f070039, tag null, or parent id 0xffffffff with another fragment for com.google.android.gms.maps.MapFragment

I solved it by declaring the view in my fragment where I called the map to static. By this way, I only create a new view if it is null, thus avoiding it to recreate the view again.

MapFragment.java

    static View rootView;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    	if(rootView==null){
    		rootView = inflater.inflate(R.layout.MapFragment, container, false);
    	}
        return rootView;
    }

MapFragment.xml

	<fragment 
	    android:id="@+id/mapview"
	    android:layout_width="match_parent"
	    android:layout_height="match_parent"
        class="com.google.android.gms.maps.MapFragment"/>

Getting Date information from MongoDB’s document objectid

This post is for mongodb java api only.


	private Date getTimeStampFromID() {
        DB db = connectDB();
        DBCollection collection = db.getCollectionFromString("database");
		DBCursor cursor = collection.find();
		while(cursor.hasNext()){
			return (new Date(((ObjectId)cursor.next().get(TAG_ID)).getTime()));
		}
	}