Friday, March 23, 2012

Enable Button Inside A List Item

Probably most of us needed this kind of rich ListView items that contains several views including buttons. For example when you're building an iOS like ListView that have "Delete" buttons in every list item.

Having a button means that you need to listen the click events on that button. But, if the button is inside a list item, you can not simply sense the clicks to the button, because ListView's OnItemClickListener overwhelms all the click events on that item. In order to avoid this and make your button clickable you need to do the following changes...

At first you need to set android:focusable and android:focusableInTouchMode attributes of your button inside the list item to "false".

<Button
 .....
 android:focusable="false"
 android:focusableInTouchMode="false"
 .....
 >
</Button>

The next thing you need to do is setting an OnClickListener to your button inside your list adapter class. You can achieve this by adding a parameter to your adapter's constructor and/or adding a setter method to the adapter that sets the button's OnClickListener.

In my example I put an OnClickListener instance as a field in my adapter and I set it in my constructor and also added a setter for the field.



public class MyAdapter extends BaseAdapter {
 .....
 public OnClickListener listener;

 .....
 public MyAdapter (Context context, OnClickListener listener) {
  this.context = context;
  mInflater = LayoutInflater.from(this.context);
  this.listener = listener;
 }

 public void setButtonListener(OnClickListener listener) {
  this.listener = listener;
 }

 .....

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  
  if (convertView == null) {
   convertView = 
    mInflater.inflate(R.layout.my_list_row, null);

   holder = new ViewHolder();
   ...
   holder._button = 
    (Button) convertView
     .findViewById(R.id.listRowButton);
   ...
   convertView.setTag(holder);

  } else {
   holder = (ViewHolder) convertView.getTag();
  }

  .....

  if (this.listener != null) {
   holder._button.setOnClickListener(this.listener);
  }
  .....
 }
}


And lastly you need to set an OnClickListener to your adapter instance where you set your ListView's adapter inside your Activity. And this is the tricky part that you need to sense which list item's button has received a click event by by using a for loop. (It doesn't look so efficient, but this was the easiest way to achieve my goal, so I did it like this. If you have any other efficient solutions please provide a comment.)


ListView myList = (ListView) findViewById(R.id.myList);

// Firstly I set the OnClickListener as null.
MyAdapter adapter = new MyAdapter(this, null);

.....
// Here is where I set the listener for button inside list item.
myAdapter.setButtonListener(new OnClickListener() {

 @Override
 public void onClick(View v) {
  for (int i = 0; i < _listView.getChildCount(); i++) {
   if (v == _listView
    .getChildAt(i).findViewById(R.id.listRowButton))
   {

    // Do Something on Button Click

   }
  }
 }
}});
.....

myList.setAdapter(myAdapter);


That's it! You can do whatever with your list item's button now. You can also use the same procedure with CheckBoxes, RadioButtons or any other Views.

Enjoy!

Friday, January 21, 2011

Force Apps to Move to SD Card (on Froyo)

In my last post I've explained about how to make your application installable to SD Card. Later I found this great blog post about moving any other application to SD Card, without having the source code. After following those steps, you will be able to move (to SD) all the applications you downloaded and installed.

So this is not only for developers, but also for standard users:

http://www.lorinbute.com/posts/how-to-force-apps-to-move-to-the-sd-card-on-froyo.html

Enjoy!

Friday, January 14, 2011

How to Enable Move to SD Card Feature for Your App?

Well, because I was busy during last several months, I couldn't post anything to my blog. Now it's time to continue posting.

Today's issue is enabling the App2SD feature for an application. As you know, when Google introduced the Froyo, they clearly stated that it would have the App2SD. So it is, but with a difference. They made it up to developers to allow the application movement to the SD card. If the user has Android 2.2 installed on their device and you haven’t applied this tip, they’ll see an unuseful, grayed out, button when they try to move the application to their SD card. Developers must specifically enable this feature within their applications.

Now it's time to learn how to do it for our applications, i will explain step by step.

First we should modify your Manifest file as follows to add android:installLocation entry to the <manifest> tag:



   <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.yourpackagename"
      android:versionCode="1"
      android:versionName="1.0"
      android:installLocation="auto">
 


We set the value to “auto” so that the users of our application will be able to decide where to install the application. Another possible values could be “internalOnly” which is the same as the behavior without this setting, and “preferExternal,” which will install the application on the SD card first, if it’s available.

After we set the installLocation key, we will get the following error:


error: No resource identifier found for attribute ‘installLocation’ in package ‘android’ 


This is because we didn't target our project to API Level 8. If we don't target the application to API Level 8, it can't have the App2SD feature. In order to do this we must change the project property "build target". Simply navigate to Properties (right-click on the project in Eclipse) and choose a target with at least API Level 8.

Now our application is ready to move to SD Card of any Android 2.2 device.

Load the application to a 2.2 device or emulator, then navigate to application management. You will see the "Move to SD" button enabled for the application.

Enjoy!

Saturday, July 31, 2010

Live Camera Preview on Android

Android SDK provides a full control on Android devices' hardware, so that you can use any component of your device in your applications. Thanks to this feature, you can use your device's camera to obtain live camera preview in your application. So that, you can build your own camera application with additional features.

Basically in a camera application, you need a camera surface and a button to take photos. First we start with getting required permission for Camera component. Also put a control into the activity tag to keep screen in landscape mode.


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

 <activity .......
    android:screenOrientation="landscape" ...... >


Then we create a simple layout includes a SurfaceView and a Button.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="horizontal"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent">

 <SurfaceView
  android:id="@+id/preview"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:layout_weight="1">
 </SurfaceView>

 <Button
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:id="@+id/buttonTakePhoto"
  android:text="Click"
  android:gravity="center">
 </Button>

</LinearLayout>

Now we are ready to build our application to put the camera preview into our SurfaceView and to set the button's behavior for taking photos. Our activity must implement the SurfaceHolder.Callback interface in order to provide a camera preview.


 // Let's name our Activity as CamDroid.
public class CamDroid extends Activity implements SurfaceHolder.Callback

Then we create our Camera, Surface and Button fields which will be initialized when our activity is started.


    private Camera mCamera;
    private Button takePictureButton;
    private SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder;

After this fields we need to declare which actions will be performed when user takes a photo.


    Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
        public void onPictureTaken(byte[] data, Camera c) {
         
         FileOutputStream outStream = null;
          try {
          
          // Directory and name of the photo. We put system time
          // as a postfix, so all photos will have a unique file name.
          outStream = new FileOutputStream("/sdcard/CamDroid_" +
              System.currentTimeMillis()+".jpg");
          outStream.write(data);
          outStream.close();
          Log.d(TAG, "onPictureTaken - wrote bytes: " + data.length);
         } catch (FileNotFoundException e) {
          e.printStackTrace();
         } catch (IOException e) {
          e.printStackTrace();
         } finally {
        }

            Log.e(TAG, "PICTURE CALLBACK: data.length = " + data.length);
            mCamera.startPreview();
        }
    };

Now we can implement the onCreate method of the Activity to initialize our surface and Button.


    public void onCreate(Bundle icicle)
    {
        super.onCreate(icicle);

        // We don't need a title for our camera window.
        // It makes our view smaller.
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        Log.e(TAG, "onCreate");
        getWindow().setFormat(PixelFormat.TRANSLUCENT);
        // In my case, name of the layout file is camdroid.xml
        setContentView(R.layout.camdroid);

        // Initialize the surface
        mSurfaceView = (SurfaceView)findViewById(R.id.preview);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(this);
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        
        // Initialize the Button
        takePictureButton = (Button)findViewById(R.id.buttonTakePhoto);
        
        // Set the button's behavior
        takePictureButton.setOnClickListener(new OnClickListener() {
         public void onClick(View v) {
          mCamera.takePicture(null, null, mPictureCallback);
         }
        });
    }

Then we must provide some methods for our surface to create first preview, change preview, and stop preview.


    // Create camera preview.
    public void surfaceCreated(SurfaceHolder holder)
    {
        Log.e(TAG, "surfaceCreated");
        mCamera = Camera.open();
        //mCamera.startPreview();
    }

    // Change preview's properties (i.e. size or format).
    public void surfaceChanged(SurfaceHolder holder,
          int format, int w, int h)
    {
        Log.e(TAG, "surfaceChanged");

        // XXX stopPreview() will crash if preview is not running
        if (mPreviewRunning) {
            mCamera.stopPreview();
        }

        Camera.Parameters p = mCamera.getParameters();
        p.setPreviewSize(w, h);
        mCamera.setParameters(p);
        try {
         mCamera.setPreviewDisplay(holder);
        } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
        }
        mCamera.startPreview();
        mPreviewRunning = true;
    }

    // Stop the preview.
    public void surfaceDestroyed(SurfaceHolder holder)
    {
        Log.e(TAG, "surfaceDestroyed");
        mCamera.stopPreview();
        mPreviewRunning = false;
        mCamera.release();
    }

Now we have a basic camera application which has a camera preview and a button on screen. You can start taking photos with your applications by pressing the button on the screen. Or you can add this method to use your device's built-in "OK" Button (Trackpad for HTC, OK Button for Samsungs etc.) for taking photos.


    public boolean onKeyDown(int keyCode, KeyEvent event)
    {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            return super.onKeyDown(keyCode, event);
        }
 
        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
            mCamera.takePicture(null, null, mPictureCallback);
            return true;
        }

        return false;
    }

ScreenShot:

Enjoy your new camera applications and take good photos :)

Wednesday, July 28, 2010

Create your own Browser using WebView

Using a WebView activity, you can display webpages over the Internet or display webpages or any other content from your device's drive. You might use this webview as a Webkit in your applications to display web contents, which can even have integrated Javascripts.


WebView activity will use the Internet, so you must add the Internet usage permission in your AndroidManifest.xml file.


 <uses-permission android:name = "android.permission.INTERNET"/>
In order to create a WebView, firstly you must create your layout including a WebView content. You can put a WebView into your layout xml file and in set its width and height as "fill_parent" to reach a fullscreen view.


Then in your main Activity, define a WebView and associate it with your layout.

 mWebView = (WebView) findViewById(R.id.web_view);
For a WebView you have a few choices about displaying contents. You can open a URL, you can create your HTML code inside your Activity and display it, you can open HTML files from your device's drive and also you can display other contents from your device's drive.


 // Loading a URL
 mWebView.loadUrl("http://www.androtips.com");

 // Loading HTML code created in the Activity
 String data = "<html><body><h2>Hello WebView</h2></body></html>";
 String mimeType = "text/html";
 String encoding = "utf-8";
 mWebView.loadData(data , mimeType , encoding);
 // Loading an HTML file or any content from sd card
 String filePath = "file:///data/data/com.webkitdemo/test.html";
 mWebView.loadUrl(filePath);

Now you have a basic WebView to display your contents. The problem with this default WebView is, when you click to a link in the webpage, Android will attempt to open its default Browser. Of course we want to open any links from our WebView open in our own WebView. To do this, we must add this small inner-class to our Activity.

 private class mWebViewClient extends WebViewClient {
    
     /** Opens new links in the same WebView instead of opening it in Browser Application.
* 
      */
     @Override
        public boolean shouldOverrideUrlLoading(WebView view , String url) {
view.loadUrl(url);
            return true;
        }
    }

Another good feature to add to our activity is setting the behavior of the Back button of device. So that we can go back from a link we went from our WebView.

 @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
            mWebView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

Because we have small display sizes on mobile devices, we might need to add zoom controls to our WebView to enhance readability. In order to add zoom controls, you must add this controls into your onCreate method.

 @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        ...
// Zoom controls
        FrameLayout mContentView = (FrameLayout) getWindow().getDecorView().findViewById(android.R.id.content);
        final View zoom = this.mWebView.getZoomControls();
        mContentView.addView(zoom, ZOOM_PARAMS);
        zoom.setVisibility(View.GONE);
...
...
}

Your WebView is ready to use now. You can display any content in this WebView and integrate it into your Applications.


Enjoy!

Monday, July 26, 2010

Development Using Eclipse IDE



In this first blog post about Android Development, I would like to explain how to start development using Eclipse IDE and Android SDK (On MS Windows).


  1. Firstly you must download and install Java SE Development Kit (JDK) in order to use Eclipse IDE.
  2. Then download the Android SDK.
  3. After downloading, create a directory named android, on your local disk C. (C:\android)
  4. Extract the android_sdk zip file into the C:\android directory.
  5. Now you need an easy setting in order to use Android SDK on Windows. Right-click to Computer, then click Properties. In the Properties window, open Advanced tab. Click the Environment Variables button at bottom-right side.,
  6. In the User Variables view, double-click the Path to change this variable. As Variable Value, write C:\Program Files\Java\jre6bin then click OK.
  7. In the System Variables view, double-click the Path to change this variable. Add the android tools directory to the end of the current value in Variable Value as C:\android\tools then click OK.
  8. Now you are ready to use Eclipse IDE. You can download the latest version of Eclipse from the official download page. You can choose the type of your operating system from the list and start download.
  9. Create a directory named eclipse, in your local disk C.(C:\eclipse)
  10. Extract the eclipse zip file into the C:\eclipse directory.
  11. Double-click eclipse.exe to open Eclipse IDE and specify your workplace directory as you wish.
  12. In the Eclipse main window, click Help > Software Updates. Then click on Available Software tab and click on Add Site button.
  13. In the Add Site window, write https://dl-ssl.google.com/android/eclipse as Location value.
  14. Then click the checkbox of the site you added and click Install Software button.
  15. After installing, Eclipse will restart itself.
  16. Now click Window > Preferences on Eclipse menu. Choose Android from left frame and write C:\android to the SDK Location box.

Saturday, July 24, 2010

Hello Android

I know that there are lots of Android Development Blogs over the Internet, but i just would like to open my own blog to share my experiences on Android Development. In this blog, you will find useful tips and Android programming examples, which I tried and used for my projects.








I hope you will find this blog useful, and please leave comments if you have advices for me.

Hello again and enjoy!