lunes, 25 de agosto de 2014

Android: Intent for showing turn-by-turn (how to get to location)


 private void showRouteToLocation(int position) {

        PointOfSaleModel pointOfSale = clientsAdapter.getItem(position);

        String format = "http://maps.google.com/maps?saddr=%s,%s&daddr=%s,%s";

        UserLocation userLocation = GPSHelper.getInstance().getLastKnownLocation(getActivity());

        String userLatitude = formattedDouble(userLocation.getLat());
        String userLongitude = formattedDouble(userLocation.getLon());

        String destinationLatitude = formattedDouble(pointOfSale.getLatitud());
        String destinationLongitud = formattedDouble(pointOfSale.getLongitud());

        String request = String.format(format, userLatitude, userLongitude, destinationLatitude,
                destinationLongitud);

        Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(request));
        startActivity(intent);
    }

jueves, 21 de agosto de 2014

Android: Extending linear layout

Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:custom="http://schemas.android.com/apk/res/<app package>"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

        <com.vogella.android.view.compoundview.ColorOptionsView
            android:id="@+id/view1"
            android:layout_width="match_parent"
            android:layout_height="?android:attr/listPreferredItemHeight"
            android:background="?android:selectableItemBackground"
            android:onClick="onClicked"
            custom:titleText="Background color"
            custom:valueColor="@android:color/holo_green_light"
             />

        ...


</LinearLayout>

Class
public class ColorOptionsView extends LinearLayout {

  private View mValue;
  private ImageView mImage;

  public ColorOptionsView(Context context, AttributeSet attrs) {
    super(context, attrs);

    TypedArray a = context.obtainStyledAttributes(attrs,
        R.styleable.ColorOptionsView, 0, 0);
    String titleText = a.getString(R.styleable.ColorOptionsView_titleText);
    int valueColor = a.getColor(R.styleable.ColorOptionsView_valueColor,
        android.R.color.holo_blue_light);
    a.recycle();

    LayoutInflater inflater = (LayoutInflater) context
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    inflater.inflate(R.layout.view_color_options, this, true);

    TextView title = (TextView) getChildAt(0);
    title.setText(titleText);

    mValue = getChildAt(1);
    mValue.setBackgroundColor(valueColor);

    mImage = (ImageView) getChildAt(2);
  }

  public ColorOptionsView(Context context) {
    this(context, null);
  }

  public void setValueColor(int color) {
    mValue.setBackgroundColor(color);
  }

  public void setImageVisible(boolean visible) {
    mImage.setVisibility(visible ? View.VISIBLE : View.GONE);
  }

}

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

    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_centerVertical="true"
      android:layout_marginLeft="16dp"
        android:textSize="18sp"
        />

  <View
      android:layout_width="26dp"
      android:layout_height="26dp"
      android:layout_centerVertical="true"
      android:layout_marginLeft="16dp"
      android:layout_marginRight="16dp"
      />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
      android:layout_marginRight="16dp"
        android:layout_centerVertical="true"
        android:visibility="gone"
        />
   
</merge>

attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ColorOptionsView">
        <attr name="titleText" format="string" localization="suggested" />
        <attr name="valueColor" format="color" />
    </declare-styleable>

</resources>

viernes, 15 de agosto de 2014

Android: Action on keyboard enter button

Login layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="250dp"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:gravity="center"
        android:orientation="vertical" >

        <EditText
            android:id="@+id/username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:imeOptions="actionNext"
            android:hint="@string/username"
            android:singleLine="true" />

        <EditText
            android:id="@+id/pasword"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/password"
            android:imeOptions="actionGo"
            android:inputType="textPassword"
            android:singleLine="true" />

        <Button
            android:id="@+id/login_button"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_marginTop="30dp"
            android:text="@string/login" />
    </LinearLayout>

</LinearLayout>

Activity
@Override
public void onCreate(Bundle savedInstanceState) {
  
 super.onCreate(savedInstanceState);
  
 setContentView(R.layout.activity_login);
  
 EditText password = (EditText) findViewById(R.id.editPass);
 password.setOnKeyListener(new OnKeyListener() {

  public boolean onKey(View view, int keyCode, KeyEvent event) {

   if (event != null && event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER) {
      
    doLogin();
    return true;
   } else {
    return false;
   }
  }
 });

 Button loginBtn = (Button) findViewById(R.id.btnLogin);
 loginBtn.setOnClickListener(this);
}

//...
@Override
public void onClick(View v) {

 if (v.getId() == R.id.btnLogin) {
  doLogin();
 }
}

miércoles, 13 de agosto de 2014

Android: Network task

NetworkTask

package ar.com.fennoma.asi.tasks;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import ar.com.fennoma.asi.R;

/**
 * The downside of this class is that you have to override non-traditional
 * methods rather than overriding: onPreExecute, onPostExecute, and
 * doInBackground.
 */
public abstract class NetworkTask<Params, Progress, Result> extends
        AsyncTask<Params, Progress, TaskResult> {

    public interface ICallBack<Result> {

        public void onError(Result result);

        public void onSuccessful(Result result);
    }

    private ICallBack<TaskResult> callback;
    protected Context context;

    public NetworkTask(Context context, ICallBack<TaskResult> callback) {

        this.context = context;
        this.callback = callback;
    }

    // We won't let extending classes to override this method to prevent them
    // from not calling the callback
    @Override
    protected final void onPostExecute(TaskResult response) {

        if (callback != null) {

            if (response.error) {

                callback.onError(response);

            } else {

                callback.onSuccessful(response);
            }
        }

        onPostProcessing(response);
    }

    protected void onPostProcessing(TaskResult response) {
    }

    // We won't let extending classes to override this method to prevent them
    // from skipping the check
    @Override
    protected final TaskResult doInBackground(final Params... params) {

        try {

            if (context == null) {

                throw new IllegalArgumentException("Context cannot be null");
            }

            if (deviceHasAnActiveConnection()) {

                return this.doOnActiveConnection(params);

            } else {

                doOnNoActiveConnection(params);

                return createNoConnectionResult();
            }

        } catch (final Exception e) {

            doOnException(e, params);

            return createExceptionResult(e);
        }
    }

    private TaskResult createNoConnectionResult() {

        TaskResult taskResult = new TaskResult();
        taskResult.error = true;
        taskResult.exception = false;
        taskResult.message = context.getString(R.string.no_connection);

        return taskResult;
    }

    private TaskResult createExceptionResult(Exception e) {

        TaskResult taskResult = new TaskResult();
        taskResult.error = true;
        taskResult.exception = true;
        taskResult.message = context.getString(R.string.exception);

        return taskResult;
    }

    private boolean deviceHasAnActiveConnection() {

        ConnectivityManager systemService = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo activeNetworkInfo = systemService.getActiveNetworkInfo();

        return (activeNetworkInfo != null) && activeNetworkInfo.isConnected()
                && activeNetworkInfo.isAvailable();
    }

    protected abstract TaskResult doOnActiveConnection(Params... params) throws Exception;

    // Hook methods
    /**
     * The callback will be called on "onPostExecute" so there is no need to do
     * it in here.
     * 
     * @param params
     */
    protected void doOnNoActiveConnection(Params... params) {

    }

    /**
     * The callback will be called on "onPostExecute" so there is no need to do
     * it in here.
     * 
     * @param params
     */
    protected void doOnException(Exception e, Params... params) {

    }
}

You will need to add the following permission to the manifest:

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

Android: Base activity

Base activity

public class BaseActivity extends FragmentActivity{

 private Dialog loadingDialog;

 protected List<AsyncTask> tasks;
 protected List<Toast> toasts;

 @Override
 protected void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);

  tasks = new LinkedList<AsyncTask>();
  toasts = new LinkedList<Toast>();
}

 @Override
 protected void onPause() {

  super.onPause();

  isVisible = false;

  this.hideLoadingDialog();

  this.cancelAllTasks();

  this.cancelAllToasts();
 }

 private void cancelAllToasts() {

  for (Toast currentToast : toasts) {
   currentToast.cancel();
  }

  toasts.clear();
 }

 public void addTask(AsyncTask task) {

  tasks.add(task);
 }

 private void cancelAllTasks() {

  for (AsyncTask currentTask : tasks) {

   if (currentTask != null && currentTask.getStatus() != Status.FINISHED) {
    currentTask.cancel(true);
   }
  }

  tasks.clear();
 }

 @Override
 public void showLoadingDialog() {

  if (loadingDialog == null) {

  // Probably should have a reference counter here
   loadingDialog = DialogHelper.buildLoadingDialog(this, this.getString(R.string.loading_dialog_loading_message));

   loadingDialog.show();
  }
 }

 @Override
 public void hideLoadingDialog() {

  if (loadingDialog != null) {

  // And here we decrement that counter and dismiss the dialog if it reaches 0
   loadingDialog.dismiss();
   loadingDialog = null;
  }
 }
 
 @Override
 public void onDestroy() {

  super.onDestroy();

  MemoryManagementHelper.unbindDrawables(((ViewGroup) findViewById(android.R.id.content)).getChildAt(0));
  System.gc();
 }

}
MemoryManagementHelper

public class MemoryManagementHelper {

 public static void unbindDrawables(View view) {
  if (view != null) {
         if (view.getBackground() != null) {
          view.getBackground().setCallback(null);
         }
         
         if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
             for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
              unbindDrawables(((ViewGroup) view).getChildAt(i));
             }
             ((ViewGroup) view).removeAllViews();
         }
  } else {
   // TODO - ?
  }
    }
}

lunes, 11 de agosto de 2014

Android: "Smart" enum class


private enum Key {

  TRANSPARENCY("transparecy"); 

  private String stringValue;

  Key(String stringValue) {

   this.stringValue = stringValue;
  }

  @Override
  public String toString() {

   return this.stringValue;
  }

  public static Key getEnum(String stringValue) {

   if (stringValue == null) {
    throw new IllegalArgumentException();
   }

   for (Key key : values()) {

    if (stringValue.equalsIgnoreCase(key.toString())) {
     return key;
    }
   }

   throw new IllegalArgumentException();
  }
 }

jueves, 7 de agosto de 2014

Android: startActivityForResult

In caller
Intent i = new Intent(this, SecondActivity.class);
startActivityForResult(i, 1);
In Activity that handles the intent
Intent returnIntent = new Intent();
returnIntent.putExtra("result",result);
setResult(RESULT_OK, returnIntent); // Or RESULT_CANCELED
finish()
In caller
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    if (requestCode == 1) {

        if(resultCode == RESULT_OK){
            String result=data.getStringExtra("result");

        } else if (resultCode == RESULT_CANCELED) {
            //Write your code if there's no result
        }
    }
}

miércoles, 6 de agosto de 2014

Android: Popup menu

 private PopupWindow initiatePopupWindow(View anchor) {

  try {

   LayoutInflater layoutInflater = (LayoutInflater) getApplicationContext()
     .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
   View layout = layoutInflater.inflate(R.layout.test_row, null);

   layout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
   mainMenu = new PopupWindow(layout, FrameLayout.LayoutParams.MATCH_PARENT,
     FrameLayout.LayoutParams.WRAP_CONTENT, true);
   Drawable background = getResources().getDrawable(
     android.R.drawable.editbox_dropdown_dark_frame);
   mainMenu.setBackgroundDrawable(background);
   mainMenu.showAsDropDown(anchor, 0, 0);

   setOnClickListeners(layout);

  } catch (Exception e) {
   e.printStackTrace();
  }
  return mainMenu;

 }

Android: Attributes application namespace in layout

xmlns:app="http://schemas.android.com/apk/res-auto"

martes, 5 de agosto de 2014

Photoshop: Batch

Create script

1) "Window" > "Actions".
2) At the bottom select the sheet like icon and press "Rec" (circle icon) and do whatever you need to do

Run script

3) "File" > "Automate" > "Batch" and select the configuration you want. If you want the same name and extention don't touch that part.

Android: Drawing

Draw dashed box

public class DashedBox extends View {

 private Paint paint;


 public DetectionRectangle(Context context) {
  
  super(context);
  
  createPaint();
 }

 private void createPaint() {
  
  paint = new Paint();
  paint.setColor(Color.WHITE);
  paint.setStyle(Style.STROKE);
  paint.setStrokeWidth(convertToPx(2));
  paint.setPathEffect(new DashPathEffect(new float[] { 20, 5 }, 0));
  
  setLayerType(View.LAYER_TYPE_SOFTWARE, null); // Mandatory else it won't draw the dash but a full line
 }
 
 private int convertToPx(int dp) {
     // Get the screen's density scale
     final float scale = getResources().getDisplayMetrics().density;
     // Convert the dps to pixels, based on density scale
     return (int) (dp * scale + 0.5f);
 }

 public DetectionRectangle(Context context, AttributeSet attrs) {
  
  super(context, attrs);
  
  createPaint();
 }

 public DetectionRectangle(Context context, AttributeSet attrs, int defStyleAttr) {
  
  super(context, attrs, defStyleAttr);
  
  createPaint();
 }

 
 @Override
 protected void onDraw(Canvas canvas) {
  
  super.onDraw(canvas);
  
  canvas.drawLine(0, 0, getWidth(), 0, paint); // Top line
  canvas.drawLine(0, 0, 0, getHeight(), paint); // Left line
  canvas.drawLine(0, getHeight(), getWidth(), getHeight(), paint); // Bot line
  canvas.drawLine(getWidth(), 0, getWidth(), getHeight(), paint); // Right line
 }
}

Android: DP to pixels


public int convertToPx(int dp) {
    // Get the screen's density scale
    final float scale = getResources().getDisplayMetrics().density;
    // Convert the dps to pixels, based on density scale
    return (int) (dp * scale + 0.5f);
}