Sunday, December 29, 2013

Custom Views

We get Custom Views by extending an existing Widget ( Button, EditText, TextView, etc ), something that fits better to the functionality we want to achieve and by defining attributes for that view.

1. By extending a View we now have a Class, whose fully qualified name can be used as an XML tag, to add to the layout file. If the package is com.androidexamples.customviews and my Custom View's Class name is MyEditText then the XML code we are going to add is :

<com.androidexamples.customviews.MyEditText
    android:id=”@+id/myview”
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
        …

/>

2. Into res/values/attrs.xml inside a <declare-styleable> tag we add the attributes for our view. A valid example could be :

<resources>
        <declare-styleable>
            <attr name=”attr_color” format=”color” />
            <attr name=”attr_firstname” format=”string” />
       </declare-styleable>
</resources>


From now on we can use these attributes either in our layout file as part of our custom View XML tag, or through code.
In order to use them in the layout file we have to first define a custom namespace similar to what android does with its own attributes. The android default namespace is : xmlns:android="http://schemas.android.com/apk/res/androidand it's defined into the parent element of the layout file.
Respectively our attributes' namespace uses the same format but instead of android we can use whatever name we want ( like “app” or “custom” ) and the schema is defined with our package name instead of the android. So a valid example could be :
xmlns:app="http://schemas.android.com/apk/res/com.androidexamples.customviews"

Now we can add the “attr_firstname” to the XML in the form : 
                       app:attr_firstname=”Some Random Text”


Through the code we have access to an array that stores each attribute. It is a special container named TypedArray and it can get referenced to the attributes with obtainStyledAttributes().


3. In our Class code it is a common practise to use an init() method to get the attributes and assign initial values to them. This method is then passed to our View's constructor.

4. Then all it's left to do is to override the onDraw() and onMeasure() methods.


By overriding onDraw() we have access to the Canvas object. You can now create your UI for your View. The styling of the elements is done through a Paint object.


OnMeasure() is called with the width and height specifications from the parent layout element. Those values should be treated as requirements for the restrictions on width and height measurements we will produce.


Some key points you should keep in mind ( otherwise it leads you to hard ) :
  • call recycle() after you get the attributes from TypedArray.
  • Don't create Paint objects inside onDraw() method. Views are redrawn frequently and creating objects inside onDraw() its expensive waste of resources.
  • After every change on our attributes' values we have to call invalidate() so the system will know there might be a change in its appearance and needs to be redrawn.



The code below gives as a custom EditText which uses Paint to underline each line with a light green color.




public class MyEditText extends EditText {

 private Rect mRect;
 private Paint mPaint;
  
 private int attrColor;
 
 
 public MyEditText(Context context) {
  super(context);
 }

 public MyEditText(Context context, AttributeSet attrs) {
  super(context, attrs);
  
  TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyEditText);
     attrColor = ta.getInteger(R.styleable.MyEditText_attr_color, 0xff00ff00);
     ta.recycle();
  
  init();
 }

 public void init() {
  
  mRect = new Rect();
  mPaint = new Paint();
  mPaint.setStyle(Paint.Style.FILL);
  mPaint.setColor(attrColor);    //get value from attr
  
 }
 
 
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  int count = getLineCount();
  
  Rect r = mRect;
  Paint p = mPaint;
  
  
 for(int i=0; i< count; i++)  {
   int baseline = getLineBounds(i, r);
   canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, p);
  }
  
 }
 
}



Monday, December 9, 2013

Add Views programmatically

Example of adding two Buttons in a RelativeLayout :

1) Instantiate the RelativeLayout
2) Instantiate the Buttons.
3) Create the LayoutParams for each Buttons.
4) Add Views to their parent. That's the RelativeLayout.

One key point here. The LayoutParams for the child Views must the same type as that of their parent. So in our case both Buttons  LayoutParams have to be RelativeLayout.LayoutParams.

Let's see how this applies to code :

RelativeLayout layout = new RelativeLayout(this); // Instantiate the parent

b3 = new Button(this); b3.setId(1);
b3.setText("Relative Button 3");

b4 = new Button(this); b4.setId(2);
b4.setText("Relative Button 4");

RelativeLayout.LayoutParams b3_lp = new RelativeLayout.LayoutParams(
                   LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);


RelativeLayout.LayoutParams b4_lp = new RelativeLayout.LayoutParams(
                  LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
b4_lp.addRule(RelativeLayout.RIGHT_OF, b3.getId());

layout.addView(b3, b3_lp);
layout.addView(b4, b4_lp);

setContentView(layout);


The result is :



Notice the addRule() which sets the Button b4 to the right of the b3.
To achieve that we have to set Id's for our Buttons so we can refer to the view that acts as an anchor.



Sunday, November 24, 2013

Send JSON unicode data to server with POST request

HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url); // Address ( url )
HttpResponse response;

JSONObject json = new JSONObject();

json.put("passwd", param1);
json.put("comment", param2);

                        // String Entity to UTF-8
StringEntity se = new StringEntity(json.toString(), "UTF-8");
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));

httppost.getParams().setParameter("json", json);
httppost.setEntity(se);

response = httpclient.execute(httppost);

Friday, November 1, 2013

Android Studio and Gradle Basics - part 1

With Android Studio there's a new build system called Gradle. In fact Gradle is much more than just a build system but we will focus on the basics here.

First of all lets see the Project Structure :



The root folder contains two Project folders and two gradle files.

For now build.gradle is empty while settings.gradle  :
include ':MyDemo', ':MyLibProject'

Between MyDemo  and MyLibProject Project there are some differences :
1. Library Projects do not generate APK. Instead they generate an .aar package.
2. build.gradle of MyDemo contains a line apply plugin: 'android'  where for Library Project
    we  have apply plugin : 'android-plugin'

Let's have a look at MyDemo build.gradle file :

buildscript {
     repositories {
         mavenCentral()
     }
     dependencies {
          classpath 'com.android.tools.build:gradle:0.6.+'
     }
}
apply plugin: 'android'

repositories {
      mavenCentral()
}

android {
     compileSdkVersion 18
     buildToolsVersion "18.1.1"

     defaultConfig {
          minSdkVersion 8
         targetSdkVersion 18
     }
}


and MyLibProject build.gradle file :

buildscript {
     repositories {
         mavenCentral()
     }
     dependencies {
          classpath 'com.android.tools.build:gradle:0.6.+'
     }
}
apply plugin: 'android-library'

repositories {
      mavenCentral()
}

android {
     compileSdkVersion 18
     buildToolsVersion "18.1.1"

     defaultConfig {
          minSdkVersion 8
         targetSdkVersion 18
     }
}


We can take the first block code of each file ( which is the same ) and move it to the external build.gradle :


buildscript {
     repositories {
         mavenCentral()
     }
     dependencies {
          classpath 'com.android.tools.build:gradle:0.6.+'
     }
}


Android Projects have source folders ( MyDemo ) , Library Projects ( MyLibProject ) and jar file dependencies.
There are three kinds of dependencies :
1. Maven
2. jar file
3. Module

If we choose to add a dependency like ActionBarSherlock to our project from the maven repositories we go to http://search.maven.org/ , write actionbarsherlock to the input area and click search button.
What we see is :


We can use it in our build.gradle code :

 dependencies {
  compile 'com.actionbarsherlock:actionbarsherlock:4.4.0@aar'
 }

Instead of the above way we can also download the rar file, add it to the /libs folder and

 dependencies {
  compile file ('libs/actionbarsherlock.jar')
 }

Or if we had downloaded the source code and add it like a Library Project ( File > Project Structure > Modules ) and add it to the project. Then we had to add to the build.gradle 

 dependencies {
  compile project (':ActionBarSherlock')
 }

Just keep in mind that if we add an artifact as a .jar file to a libs folder and we have the same jar file in another library folder then we are going to have a conflict. We just need to have only one copy of the jar file.
That's a good reason for you to start using the maven repository and don't just add jar files. In that case if we have added the same artifact more than once there will be no conflict.

From the Command Line. Go to the root dir of your project. Gradle works with tasks.
gradlew tasks to see all available tasks.
gradlew assemble to build the project and
gradlew installDebug to install it to the connected devices.

Wednesday, September 11, 2013

Check if Google's location Service is enabled

Check if Google's location Service is enabled by the user, else open Settings > Location so the user enables them.
First get the
String locationProviders = Settings.Secure.getString(getContentResolver(),Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
contains "network" or "gps" or both values separated by comma.

If the string is empty => Google Location Service is closed and you have to prompt the user to open it. Wifi might or not be open.
If the string equals "network" => WiFi and Google Location Service are enabled.
If the string equals "network,gps" => WiFi and GPS and Location Service are enabled.

We need to create a Dialog and ask the user to take the action he wants. In our case we want the user when she clicks Yes to open the Settings > Location , so she can enable the Location Service.
We can achieve that with ACTION_LOCATION_SOURCE_SETTINGS.

The code is :

     if (locationProviders == null || locationProviders.equals("")) {
         
            new AlertDialog.Builder(this)
            .setTitle("Enable Location Service")
            .setMessage("This Application requires the use of Google Location's service.  " +
                    "Do you wish to enable this feature")
            .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    // show system settings
                    startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
                }
            })
            .setNegativeButton("No", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    // do nothing
                }
            })
            .show();
}

Link : http://stackoverflow.com/questions/10311834/android-dev-how-to-check-if-location-services-are-enabled

Sunday, July 14, 2013

Android Parsing JSON data

When we are dealing with Web Services often the response are in JSON format. That means we have to get the data and with the JSONArray and JSONObject classes parse through the response and extract the data we want.

The whole JSON schema uses the convention of name:value pair. The simplest example we can have here is the JSON Object { "foo":"bar" } where bar is value of foo.
We can easily imagine making a request to the server for a basketball player name and getting the answer in the above format.
Even better we can ask the server for the Personal Information of the player named "lebron james" and get data like position, nationality, weight, height, age, etc...
Then a valid response from the server could be like that :
{
    "age":"28",
     "position":"Forward",
     "nationality":"American",
     "weight":"113",
     "height":"203"
}
Values can be String, number, true, false, null, or even Object and Array.

You can read more about json here.


Now in our application we are going to use the schema ( and the values ) you can see in the image below.
click the image to enlarge

What we see is that we have an Object described by the String "users" and that Object's value is an Array.
Now we just need to think procedural and a) add the data to a JSONObject and from that data b) get the JSONArray described by the name "users".

So our code should look like :
       JSONObject jObj = new JSONObject(data);
       JSONArray sArr = new JSONArray();
     
       sArr = jObj.getJSONArray("users"); //getting the "users"

Now all we need to do is to iterate through the items of the Array and get the values specified by each tag ( id, username and password in our case ).


Since we don't get any response from a web server I stored the answer into a String.

The code is below :




And the XML layout file : 

The result in our Android emulator :
display JSON response from server


Wednesday, June 12, 2013

Root access with ES File Explorer

Open ES File Explore, go to settings  scroll down to Home Directory and change it to "/".
Now you have access to the entire file system.

You can read more here