Wednesday, April 27, 2011

Inent-filter to listen for internet/data connectivity status

When designing home screen widgets which tries to talk to cloud, we might be interested in knowing internet connectivity status of device. Suppoese when adding widget, data connectivity might not be available, but your would expect your widget to start collecting data, as and when device is connected to internet.

1- Check for internet connectivity / data connectivity.



private boolean checkInternetConnection() {

ConnectivityManager conMgr = (ConnectivityManager) mContext.getSystemService (mContext.CONNECTIVITY_SERVICE);

// ARE WE CONNECTED TO THE NET

if (conMgr.getActiveNetworkInfo() != null
&& conMgr.getActiveNetworkInfo().isAvailable()
&& conMgr.getActiveNetworkInfo().isConnected()) {
return true;
} else {
return false;
}

}


2 - To receive for Internet Connectivity dropped / up, listen for
'ConnectivityManager.CONNECTIVITY_ACTION' action.

IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiver(mNetworkStateIntentReceiver, filter);


3 - Whenever there is a change in connectivity i.e it could be either data connection is connected or disconnected, you will receive this event as broadcast, so in onreceive of the broadcast receiver, please check for internetconnect connection and decide whether internet is up or down.


BroadcastReceiver mNetworkStateIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(
ConnectivityManager.CONNECTIVITY_ACTION)) {

NetworkInfo info = intent.getParcelableExtra(
ConnectivityManager.EXTRA_NETWORK_INFO);
String typeName = info.getTypeName();
String subtypeName = info.getSubtypeName();
System.out.println("Network is up ******** "+typeName+":::"+subtypeName);

if( checkInternetConnection()== true )
{
"Decide your code logic here...."
}
}
}

};

Wednesday, April 13, 2011

How to dismiss your non-modal dialog, when touched outside dialog region

When you implement your dialog as non-modal dialog, means when your dialog is shown, you can interact with other elements on the screen, in such case, you might be interested to dismiss the dialog, when user touches/press/interacts with other elments on the screen. The following steps will help you to reeceive for the touch events outside your non-modal dialog.

1 - Set the flag-FLAG_NOT_TOUCH_MODAL for your dialog's window attribute

Window window = this.getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);

2 - Add another flag to windows properties,, FLAG_WATCH_OUTSIDE_TOUCH - this one is for dialog to receive touch event outside its visible region.

3 - Override onTouchEvent() of dialog and check for action type. if the action type is
'MotionEvent.ACTION_OUTSIDE' means, user is interacting outside the dialog region. So in this case, you can dimiss your dialog or decide what you wanted to perform.

public boolean onTouchEvent(MotionEvent event)
{

if(event.getAction() == MotionEvent.ACTION_OUTSIDE){
System.out.println("TOuch outside the dialog ******************** ");
this.dismiss();
}
return false;
}

Monday, March 28, 2011

how to launch pending intent

Pending Intent:

An application can create a Pending Intent, which is nothing but an intent and action to it, so that it can passed to some other applications which can execute this pendingintent as if original application executes it.

PendingIntents can be created of three types

getActivity(Context, int, Intent, int), getBroadcast(Context, int, Intent, int),
getService(Context, int, Intent, int);


You can create a pending intent to launch an activity, or service, broadcast an intent.

Let us see how to create an pendingIntent which can launch an activity and see once you have pendingIntent, how can you launch make operation on the intent.

- Create a two activities in your android project.
- One activity create an pendingIntent through 'getActivity()' api

PendingIntent pendingIntent;
Intent intent = new Intent();
intent.setClass(mContext,activity2.class);
pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);

- pass activity2 as setClass parameter to intent and create the pendingIntent.
- In activty1, for button click action, use the pendingIntent instance to perform the operation on it using 'send()' api.

Intent intent = new Intent();
try {
pendingIntent.send(mContext, 0, intent);
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here. Just log the exception message.
System.out.println( "Sending contentIntent failed: " );
}


activity1.java
---------------

package com.mani.pending;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;


public class activity extends Activity {
Button b1;
PendingIntent pendingIntent;
Context mContext;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mContext = this.getApplicationContext();
b1 = (Button) findViewById(R.id.button);
Intent intent = new Intent();
intent.setClass(mContext,activity2.class);
pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);

b1.setOnClickListener( new View.OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent();
try {
pendingIntent.send(mContext, 0, intent);

} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here. Just log the exception message.
System.out.println( "Sending contentIntent failed: " );
}
}
});

}
}


activity2.java
----------------


package com.mani.pending;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class activity2 extends Activity{

TextView v1;
public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.main);
v1 = (TextView)findViewById(R.id.text);
v1.setTextSize(30);
v1.setText("Welcome to pendinIntent");
}

}


Tuesday, January 25, 2011

How to bring spinner at end of button using custom view

I was trying to implement a spinner at the end of button, to indicate user that some background connection to internet was going on to fetch some data.

First approach i took was to implement a Frame animation.

- Create a different images of spinner at different positions and then add a each images to animationDrawable instance and set the drawable to button using
'setCompoundDrawable()' api as defined below


http://developer.android.com/reference/android/widget/TextView.html#setCompoundDrawables(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable)

When needed to start/stop use start() and stop() apis and setCompoundDrawable(null,null,null,null) to hide the drawable.



package com.mani.spinner;

import android.app.Activity;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class spinner extends Activity {
/** Called when the activity is first created. */
Drawable spinnerAnimation;
Drawable spinnerBackground;
Button b1;
Button b2;
sample view;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
view = (sample)findViewById(R.id.sampleView);

spinnerAnimation = new AnimationDrawable();
spinnerAnimation.setBounds(0, 0, 20, 20);

spinnerBackground =getApplicationContext().getResources().getDrawable(R.drawable.a1);
((AnimationDrawable)spinnerAnimation).addFrame(spinnerBackground, 200);

spinnerBackground =getApplicationContext().getResources().getDrawable(R.drawable.a2);
((AnimationDrawable)spinnerAnimation).addFrame(spinnerBackground, 200);

spinnerBackground =getApplicationContext().getResources().getDrawable(R.drawable.a3);
((AnimationDrawable)spinnerAnimation).addFrame(spinnerBackground, 200);

spinnerBackground =getApplicationContext().getResources().getDrawable(R.drawable.a4);
((AnimationDrawable)spinnerAnimation).addFrame(spinnerBackground, 200);

spinnerBackground =getApplicationContext().getResources().getDrawable(R.drawable.a5);
((AnimationDrawable)spinnerAnimation).addFrame(spinnerBackground, 200);

spinnerBackground =getApplicationContext().getResources().getDrawable(R.drawable.a6);
((AnimationDrawable)spinnerAnimation).addFrame(spinnerBackground, 200);

spinnerBackground =getApplicationContext().getResources().getDrawable(R.drawable.a7);
((AnimationDrawable)spinnerAnimation).addFrame(spinnerBackground, 200);

spinnerBackground =getApplicationContext().getResources().getDrawable(R.drawable.a8);
((AnimationDrawable)spinnerAnimation).addFrame(spinnerBackground, 200);

spinnerBackground =getApplicationContext().getResources().getDrawable(R.drawable.a9);
((AnimationDrawable)spinnerAnimation).addFrame(spinnerBackground, 200);

spinnerBackground =getApplicationContext().getResources().getDrawable(R.drawable.a10);
((AnimationDrawable)spinnerAnimation).addFrame(spinnerBackground, 200);

spinnerBackground =getApplicationContext().getResources().getDrawable(R.drawable.a11);
((AnimationDrawable)spinnerAnimation).addFrame(spinnerBackground, 200);

((AnimationDrawable)spinnerAnimation).setOneShot(false);

b1 = (Button)findViewById(R.id.button1);
b1.setCompoundDrawables(null, null, spinnerAnimation, null);
b1.setOnClickListener(new View.OnClickListener() {

public void onClick(View v) {
b1.setCompoundDrawables(null, null, spinnerAnimation, null);
((Animatable)spinnerAnimation).start();

}
});
b2 = (Button)findViewById(R.id.button2);
b2.setOnClickListener(new View.OnClickListener() {

public void onClick(View v) {

((Animatable)spinnerAnimation).stop();
b1.setCompoundDrawables(null, null, null, null);

}
});

}
}





More info on Frame animation you can check here :
http://iserveandroid.blogspot.com/2010/10/frame-animation-circular-spinner.html

I was thinking how to use one image and rotate it to bring the same effect of spinning. Then i tried this approach.

Second approach rotate animation resource

Spin.xml @res/anim folder.


xmlns:android="http://schemas.android.com/apk/res/android"
android:repeatCount="infinite"
android:duration="1000"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="0"
android:toDegrees="360" />



ImageView v1;
Animation mAnimation = AnimationUtils.loadAnimation(mContext, R.anim.spin);
v1.startAnimation(mAnimation);

Load the animation and apply to a image. But i could bring this effect to only the spinner image alone. Together with button and spinner @ end of button, i couldnt achieve using this.




Then i planned to create a custom view and create a button kinda of illusion and draw the spinner bitmap with different angles and create the effect like spinner @ end of button.

Third approach: Custom View

- Inherit from View class and over ride onDraw() method.
- Some special api's in canvas allows you to achieve the spinning of image.



canvas.drawRect(mButtonRect, mPaint);
canvas.drawText("More", 40,40, mPaint);
canvas.save();
canvas.translate(mSpinnerX,0);
canvas.rotate(mAngle,mSpinnerPivotX,mSpinnerPivotY);
canvas.drawBitmap(mSpinnerBitmap, null, mSpinnerRect, mPaint);
canvas.restore();


- there is a option in canvas to 'save' and 'restore'. using these apis we can save the canvas state and do some manipulation to new canvas, place objects whereever needed and then do restore so that canvas contents before save is drawn without disturbed.

- Like in this, a rectangle is drawn (imagine a button ) and a text on the button is drawn at correct cordinates.
- Then 'save' the canvas and move the canvas to the 80% length of the screen(or width of the button) using 'translate' and rotate the canvas by certain angle then draw the spinner bitmap. It looks like the bitmap is drawn at the end of original canvas with rotated.

- When the angle is kept incremented using a runnable and invalidate() is called, then you would see like the image is rotated at the end...!!

-make the view class implement 'Runnable" and implement run as below to call onDraw() for every angle change.


public void run()
{
if(mAngle == 360)
mAngle=45;
else
mAngle+=45;
invalidate();
mHandler.postDelayed(this, 100);
}




main.xml:
----------


android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
android:id="@+id/button1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Start"
/>
android:id="@+id/button2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Stop"
/>
android:id="@+id/image"
android:src="@drawable/spinner_white_48"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
android:id="@+id/sampleView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>




sample.java:

package com.mani.spinner;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;

public class sample extends View implements Runnable{

Bitmap mSpinnerBitmap;
Paint mPaint;
Rect mSpinnerRect;
Rect mButtonRect;
int mButtonWidth;
int mButtonHeight;
int mSpinnerX;
int mSpinnerPivotX;
int mSpinnerPivotY;
int mSpinnerWidth;
int mSpinnerHeight;
boolean mSpinnerVisible;
Runnable mTask;
float mAngle=0;

Handler mHandler = new Handler();
String mButtonText="More";
public sample(Context context,AttributeSet attrs)
{
super(context,attrs);
mSpinnerBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.spinner_white_48);
mPaint = new Paint();
mPaint.setColor(0xFF0000FF);
mPaint.setTextSize(16);

Display display = ((WindowManager)context.getSystemService(context.WINDOW_SERVICE)).getDefaultDisplay();
mButtonWidth = display.getWidth();
mButtonHeight = 70;
mSpinnerHeight = mSpinnerWidth = mButtonHeight;
mSpinnerPivotX = mSpinnerPivotY = mSpinnerWidth /2;
mSpinnerX = (mButtonWidth-mButtonHeight);
mSpinnerRect = new Rect(0,0,mSpinnerWidth,mSpinnerHeight);
mButtonRect = new Rect(0,0,mButtonWidth,mButtonHeight);
}
public void setText(String text)
{
mButtonText = text;
}
public void setTextSize(int size)
{
mPaint.setTextSize(size);
}

public void setButtonColor(Color color)
{

}
public void start()
{
mHandler.post(this);
mSpinnerVisible = true;
}

public void stop()
{
mSpinnerVisible = false;
mHandler.removeCallbacks(this);
invalidate();
}

public void run()
{
if(mAngle == 360)
mAngle=45;
else
mAngle+=45;
invalidate();
mHandler.postDelayed(this, 100);
}

@Override
public void onDraw(Canvas canvas)
{

canvas.drawRect(mButtonRect, mPaint);
canvas.drawText("More", 40,40, mPaint);
if(mSpinnerVisible == true)
{
canvas.save();
canvas.translate(mSpinnerX,0);
canvas.rotate(mAngle,mSpinnerPivotX,mSpinnerPivotY);
canvas.drawBitmap(mSpinnerBitmap, null, mSpinnerRect, mPaint);
canvas.restore();
}

}

}


Note:
If you would like to see how the canvas is rotated, create a visibleRect using view's height and width and draw a rectangle. Which will show you that entire canvas content is rotated.

Rect visibleRect;
visibleRect.set(0, 0, this.getWidth(), this.getHeight());

if(mSpinnerVisible == true)
{
canvas.save();
canvas.translate(mSpinnerX,0);
canvas.rotate(mAngle,mSpinnerPivotX,mSpinnerPivotY);
canvas.drawRect(visibleRect, mPaint);
canvas.drawBitmap(mSpinnerBitmap, null, mSpinnerRect, mPaint);
canvas.restore();
}

Thursday, January 20, 2011

Drag/Move a image in a custom view - part I

This post could be a first step of approach in moving a image in a view. With this approach you can start creating (base view and image movements) for a simple games like number puzzles, crosswords, pin ball.

1 - Create a class extends view. and override onDraw() and decide what are the contents you need to draw.

2 -To Keep moving a image in a view, we should be keep changing the x,y position of the image. This is the basic for image movement in a view

3 - In this example, a rectangle is drawn. And its position is hold in a variable ' Rect ImagePosition'

4 - When movement is detected 'ACTION_MOVE' event in 'OnTouchEvent()' function, deltaX is calcualted with the previous (x,y) and current moved (x,y) and a check is made like, whether , if the deltas are added to mImagePosition (top, left and bottom right ) is withing the visible screen. If 'yes', then deltax are added to 'Rect mImagePosition'. And invalidate() is called to draw() method to draw the rectangle. So it looks like the object is moving as when touched and moved along with the finger.


mImagePosition.left = mImagePosition.left + deltaX;
mImagePosition.top = mImagePosition.top + deltaY;
mImagePosition.right = mImagePosition.left + mImageWidth;
mImagePosition.bottom = mImagePosition.top + mImageHeight;
mImageRegion.set(mImagePosition);
prevX = positionX;
prevY = positionY;

invalidate();


Here is the complete code, i have tried out.

dragimage.java
----------------


import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.TextView;

public class dragimage extends Activity {

sample mView;
sample1 mView1;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.main);

}
}


main.xml:
----------


android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
android:id="@+id/view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>




sample.java:
-------------


package com.mani.dragimage;


import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
public final class sample extends View{
Paint mPaint;
Rect mRect;
Bitmap bitmap;
private int mTouchSlop;
private int mTouchMode;
int mScreenHeight;
int mScreenWidth;
int prevX;
int prevY;
static final int TOUCH_MODE_TAP = 1;
static final int TOUCH_MODE_DOWN = 2;
final int mImageWidth = 100;
final int mImageHeight = 100;
Rect mImagePosition;
Region mImageRegion;
boolean canImageMove;

public sample(Context context,AttributeSet attrs)
{
super(context,attrs);
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.chrome);
mPaint = new Paint();
mPaint.setTextSize(25);
mPaint.setColor(0xFF0000FF);
//Size for image
mImagePosition = new Rect(10,10,mImageWidth,mImageHeight);
mImageRegion = new Region();
mImageRegion.set(mImagePosition);
final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
Display display = (WindowManager)context.getSystemService(context.WINDOW_SERVICE)).getDefaultDisplay();
mScreenHeight = display.getHeight();
mScreenWidth = display.getWidth();
canImageMove = false;
}


public boolean onTouchEvent(MotionEvent event)
{
int positionX = (int)event.getRawX();
int positionY = (int)event.getRawY();

switch(event.getAction())
{
case MotionEvent.ACTION_DOWN: {
mTouchMode = TOUCH_MODE_DOWN;

if(mImageRegion.contains(positionX, positionY))
{
prevX = positionX;
prevY = positionY;
canImageMove = true;
}
}
break;

case MotionEvent.ACTION_MOVE:
{
if(canImageMove == true)
{
// Check if we have moved far enough that it looks more like a
// scroll than a tap
final int distY = Math.abs(positionY - prevY);
final int distX = Math.abs(positionX - prevX);

if (distX > mTouchSlop || distY > mTouchSlop)
{
int deltaX = positionX-prevX ;
int deltaY = positionY-prevY;
// Check if delta is added, is the rectangle is within the visible screen
if((mImagePosition.left+ deltaX) > 0 && ((mImagePosition.right +deltaX) < mScreenWidth ) && (mImagePosition.top +deltaY) >0 && ((mImagePosition.bottom+deltaY)))
{
// invalidate current position as we are moving...
mImagePosition.left = mImagePosition.left + deltaX;
mImagePosition.top = mImagePosition.top + deltaY;
mImagePosition.right = mImagePosition.left + mImageWidth;
mImagePosition.bottom = mImagePosition.top + mImageHeight;
mImageRegion.set(mImagePosition);
prevX = positionX;
prevY = positionY;

invalidate();
}
}
}
}
break;
case MotionEvent.ACTION_UP:
canImageMove = false;
break;
}
return true;
}

@Override
public void onDraw(Canvas canvas)
{
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);

// make the entire canvas white
paint.setColor(Color.CYAN);
Rect rect = new Rect(0,0,this.getWidth(),this.getHeight());
canvas.drawRect(mImagePosition, paint);
//canvas.drawBitmap(bitmap, null,mImagePosition, null);
}


}

Monday, January 17, 2011

Important framework structures/directories in android

Framework structure

Many would be working on android framework level to achieve something which is common across android system wide ( ex. it will be seen across all android applications like activity switching animations, status bar changes,any UI component changes )

I would like to share what are the important folder structures available and what are the important jar files created , how are they created , compilation sequences.

Below are the three main important jar files created in /out/target/generic/system/framework for make @ root level of AOSP......!!

1 - framework.jar
/framework/base --> Android.mk

Some of the important items which gets build as a part of this jar are

- all widgets, view groups, notification aidl...

2 - services.jar
/framework/base/services/java --> Android.mk

- All system level services are defined here, ex. statusBarService, NotificationManagerService,
- status bar view creation, designining is handled here.

3 - android.phone_policy.jar
/framework/base/policies/impl/phone -->Android.mk

4 - framework-res.apk
/framework/base/core/res/ -->Android.mk + AndroidManifest.xml

This is not a jar. An apk is created, which has a critical importance in framework. The resources present in framework are compiled and an intermediate R.java is created as a part of this apk compilation.

/out/target/common/obj/APPS/framework-res_intermediates/src/android/R.java
/out/target/common/obj/APPS/framework-res_intermediates/src/com/R.java

These R.java s are important while compiling rest of framework code. So if u take a look at Android.mk file present in framework/base, this intermediate R.java file is included while compilation.



fg-res-source-path := APPS/fg-res_intermediates/src
# $(fg-res-source-path)/com/fusiongarage/R.java
LOCAL_INTERMEDIATE_SOURCES := \
$(framework-res-source-path)/android/R.java \
$(framework-res-source-path)/android/Manifest.java \
$(framework-res-source-path)/com/android/internal/R.java \
$(fg-res-source-path)/com/fusiongarage/R.java


Further all services declaration, permission declarations, and some activities declarations are defined as a part of framework-res.apk's AndroidManifest.xml


Compilation process:

- When framework code is getting compiled there are intermediates folder created before creating the final Dex file(framework.jar,services.jar) which only can be run on android system.

For each compilation of Android.mk file there will be a intermediates folder created in 'out/target/common/obj/JAVA_LIBRARIES/'
If the android.mk file is defined to create java library out of it,it should have the below definition in it..
include $(BUILD_JAVA_LIBRARY)

Similarly for if an android.mk has the specification to build an package(apk) out of it, then its intermediates will be located in 'out/target/common/obj/APPS'

Below definition is required to create an apk from an android.mk.
include $(BUILD_PACKAGE)

When the logs are analysed when the compilation is going on, below are the flow i observed. And some hints from that.

- use ' mmm frameworks/base showcommands'
to see the logs what is going on for compilation sequences.

Dex file:

- All .java files will be compiled to .class filed and a jar file will be created first 'classes.jar'. From this classes.jar , classes.dex will be created using 'dx' executable.

out/host/linux-x86/bin/dx -JXms16M -JXmx1536M --dex --output=out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/tmp/classes.dex out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/tmp/classes.jar


javalib.jar
-

touch out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/tmp//dummy
(cd out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/tmp/ && jar cf javalib.jar dummy)
zip -qd out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/tmp/javalib.jar dummy
rm out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/tmp//dummy


aapt:

out/host/linux-x86/bin/aapt add -k
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/tmp/javalib.jar out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/tmp/classes.dex
'out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.dex' as 'classes.dex'...
jar uf out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/javalib.jar -C frameworks/base preloaded-classes

Install: out/target/product/harmony/system/framework/framework.jar
acp:

out/host/linux-x86/bin/acp -fpt out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/tmp/javalib.jar out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/tmp/framework.jar

Wednesday, January 12, 2011

How to access resources from other application (.apk)




We might be interested in accessing the resources of other application. Or inflate a particular view from other applications layout xml file.In this post, we will discuss more about how to achieve this.

1 - What ever we need to access (resources or layout), we need two main things from other application .
       
1 - R.java.
Required for you during compilation time.

2 - Application's context.
Resources needs to be inflated with the correct application's 'Context' instance.Else at runtime the prog will crash.

2 - The app1(.apk) needs to be installed on the device in order for you to create app1's context instance and then inflate the resources / layouts.

app1 :
------
Create a an android application with package (com.android.app1 ) which contains resources you want to expose to others.

AndroidManifest.xml:

Manifest file doesnt have any entry for activity or application tags. it just says, under which package the resources will be present.


package="com.android.app1"
android:versionCode="1"
android:versionName="1.0">




Keep the resources you want to expose in drawables. In this case i have kept the picture named 'pic1.jpg' .

app2:

1 - Create an android application with package name com.android.app2.

we need to include the com.android.app1.R.class into app2.

2 - Select project Right click -> Properties -> Java Build Path -> Libraries -> Add External class folder -> "Choose the app1/bin folder"
Now app2 can reference 'com.android.app1.R'

And create the context for app1.

Context otherAppContext = getApplicatoinContext().createPackageContext("com.android.app1", Context.CONTEXT_IGNORE_SECURITY);
Bitmap b1 = BitmapFactory.decodeResource(otherAppContext.getResources(),com.android.app1.R.drawable.pic1);


Use the bitmap from 'app1' to apply to a Imageview.

Layout main.xml
------------------


android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
android:id="@+id/image1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@drawable/rajini"
/>
android:id="@+id/image2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>



app2.java:
-----------

package com.android.app2;


import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.widget.ImageView;


public class app2 extends Activity {
ImageView imgView;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imgView = (ImageView)findViewById(R.id.image2);
try
{
Context otherAppContext = getApplicationContext().createPackageContext("com.android.app1", Context.CONTEXT_IGNORE_SECURITY);
Bitmap b1 = BitmapFactory.decodeResource(otherAppContext.getResources(),com.android.app1.R.drawable.pic1);
BitmapDrawable bitmapDrawable = new BitmapDrawable(b1);
imgView.setBackgroundDrawable(bitmapDrawable);
}
catch(Exception e)
{

}
}
}


How to start an activity if it is not see in launcher application list.

$ am start -n com.android.app2/com.android.app2.app2
Starting: Intent { cmp=com.android.app2/.app2 }