Showing posts with label android-frameworks. Show all posts
Showing posts with label android-frameworks. Show all posts

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

Monday, January 3, 2011

How to implement your own status bar view...!!

Some of you might be interested in replacing the android provided status bar with their own creative stuffs on top of the phone, instead the standard one provided by android.In this post i am going to explain how you can replace existing android's standard status bar view with your view.

Layout for android status bar is defined in
/frameworks/base/core/res/res/layout/status_bar.xml

The inflation part is handled in StatusBarService.java
/frameorks/base/services/java/com/android/server/status/StatusBarService.java

Line no 256 ( Roughly )

private void makeStatusBarView(Context context) {
Resources res = context.getResources();
mRightIconSlots = res.getStringArray(com.android.internal.R.array.status_bar_icon_order);
mRightIcons = new StatusBarIcon[mRightIconSlots.length];

ExpandedView expanded = (ExpandedView)View.inflate(context,
com.android.internal.R.layout.status_bar_expanded, null);
expanded.mService = this;
StatusBarView sb = (StatusBarView)View.inflate(context,
com.android.internal.R.layout.status_bar, null);

...............................
...............................
...............................
}


The place where the status bar view added is

public void systemReady() {
final StatusBarView view = mStatusBarView;
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
view.getContext().getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height),
WindowManager.LayoutParams.TYPE_STATUS_BAR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING,
mPixelFormat);
lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
lp.setTitle("StatusBar");
lp.windowAnimations = R.style.Animation_StatusBar;

WindowManagerImpl.getDefault().addView(view, lp);
}


The status bar view which was inflated earlier is added to WindowManager.
WindowManagerImpl.getDefault().addView(view, lp);

In order for your view to be shown, simple, you need to bring in your 'View' instance and add it here at this point. DONE...!!

So simple isn't it...!!

But, well where will you keep your view handling/creating (i mean the .java file), how will you show default status bar notifications( like antenna, wifi, bluetooth ) every thing which a status bar shows now.

1 - Create a folder in /frameworks/base named 'mystatus'
2 - Create java and res folders and create folders inside 'java' as per package names and keep the resources, layouts files you need under res corresponding folders ( drawable-hdpi , layouts )


java->com->mani->mystatus
res->drawable-hdpi
res->drawable-mdpi
res->layouts
res->assets
res->anim ( if any required )


3 - In this way you have all your independent view creation/public exposed apis present in a seperate folder in framework.

MyStatusBarView.java



package com.mani.mystatus;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.graphics.Typeface;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.LevelListDrawable;
import android.graphics.drawable.AnimationDrawable;

public final class MyStatusBarView extends LinearLayout{

private TextView batterytext;
private TextView batterylevel;
private TextView batterypercentage;

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

}

public MyStatusBarView(Context context){
super(context);

batterytext = new TextView(context);
batterytext.setTextSize(20);
batterytext.setPadding(7,0,0,0);
batterytext.setTextColor(Color.GRAY);
batterytext.setText("MANI - My status bar");

batterylevel = new TextView(context);
batterylevel.setTextSize(22);
batterylevel.setPadding(7,0,0,0);
batterylevel.setTextColor(Color.RED);

batterypercentage = new TextView(context);
batterypercentage.setTextSize(18);
batterypercentage.setPadding(2,0,0,0);
batterypercentage.setText("%");
batterypercentage.setTextColor(Color.RED);

LinearLayout.LayoutParams textParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.FILL_PARENT);
LinearLayout.LayoutParams levelParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.FILL_PARENT);
LinearLayout.LayoutParams percentageParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.FILL_PARENT);

batterytext.setLayoutParams(textParams);
batterylevel.setLayoutParams(levelParams);
batterypercentage.setLayoutParams(percentageParams);

this.setBackgroundColor(Color.BLUE);

this.addView(batterytext);
this.addView(batterylevel);
this.addView(batterypercentage);

}


public void setBatteryLevel(int level)
{
String blevel = "";
blevel+= level;
batterylevel.setText(blevel);

}

}



Changes required in StatusBarService.java
------------------------------------------

These are the four steps you need to implement.



1- Import the view class
import com.mani.mystatus.MyStatusBarView;

2 - Declare a global variable to MyStatusBarView
MyStatusBarView myStatusBarView;

3 - Create a instance (NOTE: We are passing context obtained in StatusBarService)
myStatusBarView = new MyStatusBarView(mContext);

4 - Add the view instance to WindowManager
WindowManagerImpl.getDefault().addView(myStatusBarView, lp);


I am going to show you how to display battery percentage in the custom view. (later you can implement what are all the details you require from statusbarservice and send it back to your view using public exposed apis).

So i am going to expose a public function in MyStatusBarView class to get the battery percent and display it.
public void setBatteryLevel(int level);

In StatusBarService.java:

public void updateBatteryStats(IconData batteryData)
{
myStatusBarView.setBatteryLevel(batteryData.iconLevel);
}


In order for the framework compilation to pick up java files from 'mystatus' folder, add a entry in the file

/build/core/pathmap.mk as below.


1 - pathmap.mk /build --> Add the folder.
FRAMEWORKS_BASE_SUBDIRS := \
$(addsuffix /java, \
core \
mystatus \
graphics \
location \
media \
opengl \
sax \
telephony \
wifi \
vpn \
keystore \
)


Resources usuage:

We might be interested in using resources ( like images, layouts) in status bar view. Include your resources in res folder. Now i have two questions for you

1 - We need to have R.java file for compilation of java files in 'mystatus' (if in case if uses import com.mani.mystatus.R ).How we import these ?
2 - We need these resources to be brought to the devices. How we do this ?

For the first question

Include a entry in base/android.mk

This where framework-res R files are included before compilation.
(roughly line no 194 )

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 \

So we need to include our newly created R.java file to this path.


mystatus-source-path := APPS/mystatus-res_intermediates/src

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 \
$(mystatus-source-path)/com/mani/mystatus/R.java


For second question

When R.java files will be created ??. We need to compile the resources directory.
A resources directory will be compiled only if the compilation is for android application. ( i.e we need to create a apk out of it to see the R.java file generated)

How do we make 'mystatus' a application. ( No activity is present but that is okay )
Keep a AndroidManifest.xml under a res folder and a 'android.mk' file.

AndroidManifest.xml:









This manifest file basically tells the Resources will be under the package name 'com.mani.mystatus'

Android.mk

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_STATIC_JAVA_LIBRARIES := \
android-common

LOCAL_PACKAGE_NAME := mystatus-res

# Install this alongside the libraries.
LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)

# Create package-export.apk, which other packages can use to get
# PRODUCT-agnostic resource data like IDs and type definitions.
LOCAL_EXPORT_PACKAGE_RESOURCES := true

include $(BUILD_PACKAGE)



Android.mk file is required for you to compile the subsystem from root directory.

For more understanding of android build process, what is going on when apk is built, please check below link.

http://www.alittlemadness.com/2010/06/07/understanding-the-android-build-process/
# make mystatus-res (or) # make framework/base/mystatus/res/

'mystatus-res.apk' will be created and kept in
out/target/product/generic/system/framework

You need to push this apk also.

In order for the 'mystatus' folder to be compiled you need to compile the base.
mmm frameworks/base

out/target/product/generic/system/framework/framework.jar

framework.jar contains the dex files of 'mystatus' java files.

In order to compile the status bar service changes, compile the services part.
mmm frameworks/base/services/java

out/target/product/generic/system/framework/services.jar

services.jar will have the changes/ recent modified changes in statusbarservice.java.

So totally three files files needs to be pused the device.

adb -d remount
adb -d push out/target/product/generic/system/framework/services.jar /system/framework
adb -d push out/target/product/generic/system/framework/framework.jar /system/framework
adb -d push out/target/product/generic/system/framework/mystatus-res.apk /system/framework


For safer side, push the entire framework contents to your device.
adb -d push out/target/product/generic/system/framework/ /system/framework

So now when the system boots up, you would be seeing your own status bar view (MyStatusBarView).

Enjoy the work...!!

Snapshots for your reference:
This was tried out on vanilla android 2.2



Wednesday, December 22, 2010

How to compile Launcher / Calendar or any packages/apps from AOSP in eclipse...!!

How to compile the launcher or any app from packages/apps from eclipse

File->New > Android Project-> Create project from existing workspace ->
-> Point to any of the application in AOSP/packages/apps/AlarmClock (or) Calendar any app.

Now you would be facing many compilation errors for most of the apis.
Currently, You would be working with Android SDK.So it would be linking against android.jar provided from SDK version, in which these apis wont be available.


To make it compile in eclipse, you need to do following steps.



1 - when 'make' is made at root of AOSP, certain jar files will be created in /out directory.

/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes-full-debug.jar

2 - In eclipse, right click your project , select properties -> JAVA Build path ->Libraries tab.
You would have option as 'Add Library' in the side.
Click it. Then select 'User Library'-> 'user libraries'.

then click 'New' and give a name to it.
Then select the newly entered name and select 'Add jars' options in the side. Choose the path of the classes-debug.jar.

3 - Back to Java Build path window. Go to 'Order and export' make the newly added library to be at the top.



Done...!! Now you are ready to compile and debug as well...!!



Note :
'classes-full-debug.jar' file is nothing but collection of .classes files required for compilation. But when you want to run the apk build using this method ( eclipse ) on the emulator, we need the corresponding dex files to be present. DEX files are nothing but dalvik compiled files, which android OS requires for running your application. So you need to push the framework.jar created from compiling 'make' @ root of AOSP to the emulator /system/framework.

go to /out/target/product/generic/system/framework/framework.jar

adb -s emulator-5554 remount
adb -s emulator-5554 push framework.jar /system/framework
adb -s emulator-5554 shell reboot.



For reference eclipse screen shots:











Monday, November 8, 2010

How to apply animations when activity enters & exits in framework.??

Every time when an activity is started / entered first time, or when an activity is exited, a simple animation is performed by the framework.Currently framework performs simple fade-in and fade-out animations.

What if we like to apply our own animations when activity screen is first launched.?

It is possible. I will point out the places where you need to modify to apply you animations.

1 - Through xml

If you like to apply animations through xml then write your animation logics in these files.


frameworks/base/core/res/res/anim/activity_open_enter.xml
frameworks/base/core/res/res/anim/activity_open_exit.xml
frameworks/base/core/res/res/anim/activity_close_enter.xml
frameworks/base/core/res/res/anim/activity_open_exit.xml


These animations are given style item names in styles.xml



<style name="Animation.Activity">
<item name="activityOpenEnterAnimation">@anim/activity_open_enter</item>
<item name="activityOpenExitAnimation">@anim/activity_open_exit</item>
<item name="activityCloseEnterAnimation">@anim/activity_close_enter</item>
<item name="activityCloseExitAnimation">@anim/activity_close_exit</item>


These names are referred in frameworks while picking the resource id for animations.
ex: com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation
com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;

2 - Custom animation class.

frameworks/base/services/java/com/android/server/WindowManagerService.java

This file in services of framework is where animation is set and performs the animations for activity enter & exit.
There are two places animations are set one for activities and one for windows, where activity view is attached. Parent of all views.


private boolean applyAnimationLocked(AppWindowToken wtoken,
WindowManager.LayoutParams lp, int transit, boolean enter) --> Activity

private boolean applyAnimationLocked(WindowState win,
int transit, boolean isEntrance) ----> Windows


I added logs in both places and found that in applyAnimationLocked for activity



// Only apply an animation if the display isn't frozen. If it is
// frozen, there is no reason to animate and it can cause strange
// artifacts when we unfreeze the display if some different animation
// is running.


It dint enter into the main 'if' to set the animations. I think it is because of the above said reason.!!

So i set the animation for main window itself in the other 'applyAnimationLocked' for windows.

For testing, i took the Rotate3dAnimation.java class provided in android-sdk samples under API-Demos folder.

Create a instant of this class and set the animation.



Added the below code at line no 2739

Display display = ((WindowManager)mContext.getSystemService(mContext.WINDOW_SERVICE)).getDefaultDisplay();

int width = display.getWidth();
int height = display.getHeight();

final float centerX = width.getWidth() / 2.0f;
final float centerY = height.getHeight() / 2.0f;

// Create a new 3D rotation with the supplied parameter
// The animation listener is used to trigger the next animation
final Rotate3dAnimation rotation =
new Rotate3dAnimation(0, 0, centerX, centerY, 310.0f, true);
rotation.setDuration(500);
rotation.setFillAfter(true);
a = rotation;

win.setAnimation(a);
win.mAnimationIsEntrance = isEntrance;



This animation will be applied to all switch cases check,,which is window enter, window exit.. etc..



switch (transit) {
case WindowManagerPolicy.TRANSIT_ENTER:
attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
break;
case WindowManagerPolicy.TRANSIT_EXIT:
attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
break;
case WindowManagerPolicy.TRANSIT_SHOW:
attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
break;
case WindowManagerPolicy.TRANSIT_HIDE:
attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
break;



Now you can observe animations are applied to all types of windows...like dialog, error notes, all activitie..!!

By this you can define your own animation extending 'Animation', it can be even 3D animation and can be applied to activity enter and exit... !!

Hope it helps someone who works in framework and trying to apply animation when activity enters....!!

Sunday, November 7, 2010

Invisible activity - Why status bar is not focusable ?

I was in a situation to launch a keyboard, when a tap happens on the edittext on the status bar.
I introduced a editText in the status bar. And expected framework to launch the keyboard when tapped. But unfortunately framework doesnt popup the keyboard.

I posted in android-developers forums and got some clue by android framework engineers.

1 - When status bar view is added to windowmanager, windowManager layoutparams is set with the flag 'WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE '.

frameworks/base/services/java/com/android/server/status/StatusBarService.java



public void systemReady() {
System.out.println("Statusbar service - systemReady ");
final StatusBarView view = mStatusBarView;
WindowManager.LayoutParams lp = new
WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
view.getContext().getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height),
WindowManager.LayoutParams.TYPE_STATUS_BAR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING,
mPixelFormat);
lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
lp.setTitle("StatusBar");
lp.windowAnimations = R.style.Animation_StatusBar;
WindowManagerImpl.getDefault().addView(view, lp);
}


FLAG_NOT_FOCUSABLE Window flag: this window won't ever get key
input focus, so the user can not send key or other button events to
it.

http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_NOT_FOCUSABLE

2 - It is decided by the framework that status bar will not receive any focusable events. You can handle the touch, but it will not get any focus.!!

- I tried uncommenting that flag and checked. Then status bar window received focus, where as the other windows mainly - phone Window, where the activity window resides doesnt receive focus, so literally i couldnt do anything on the screen....:)

for more details refer here

http://groups.google.com/group/android-platform/browse_thread/thread/385fa0ede79fd7f8/e286f2ff0e6f1c16#e286f2ff0e6f1c16

So i decided to a write a invisible activity :)

Means like, if somebody taps on the status bar's edit text, i launch an activity and through that activity i launch the keyboard, giving user an illusion that keyboard is launched because of the tap on the edit text.

how do we achieve this ???

- To pop up the keyboard automatically when the activity is launched, we need a editText component in the activity.

- A runnable is created and it will be executed after the activity is launched to show the inputmethod (IME) using inputManager.Which gives user a illusion that keyboard is launched. Keyboard can be launched with any View element, Button, TextView, EditText..etc...But View has to be in foucs



@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
// Launch the IME after a bit
mHandler.postDelayed(mShowInputMethodTask, 0); --> Launch the runnable
}
}

private Runnable mShowInputMethodTask = new Runnable() { -->Runnable
public void run() {
showInputMethodForQuery();
}
};

protected void showInputMethodForQuery() { -----> Shows the IME using a View
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
if (imm != null) {
imm.showSoftInput(press, 0);
}
}



Lets see the complete example:

1- Create a simple View element in the layout.xml.. In this case i have created a button.

To make it invisible.

Apply the background, text property to color:transparent

android:textColor="@android:color/transparent"
android:background="@android:color/transparent"


Layout.xml:
------------



<?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"
>

<Button android:id="@+id/press"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/transparent"
android:background="@android:color/transparent"
android:text="@string/hello"/>

</LinearLayout>



Note:

When the keyboard is launched and when the user presses 'back' button, there is no way that inputmethodManager will let the application know that keyboard is exited.
So when back is pressed, keyboard will be dismissed and you could see a transparent window, where u cannot really do anything.

Basically it is the transparent activity which has button in it which is also a transparent one due to the settings of background color & text color.

So we need to handle the onTouchEvent() of activity and do an exit. ( this.finish() )



invisibleactivity.java
--------------------------



package com.android.urldisplay;

import android.app.Activity;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.view.Display;
import android.widget.LinearLayout;
import android.view.ViewGroup;
import android.view.Gravity;

public class invisibleactivity extends Activity
{

private static final int APP_ID = 0;
private Handler mHandler = new Handler();
Button press;

private Runnable mShowInputMethodTask = new Runnable() {
public void run() {
showInputMethodForQuery();
}
};

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);


}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
// Launch the IME after a bit
mHandler.postDelayed(mShowInputMethodTask, 0);
}
}
protected void showInputMethodForQuery() {
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
if (imm != null) {
imm.showSoftInput(press, 0);
}
}
public boolean onTouchEvent (MotionEvent event)
{
this.finish();
return true;
}
}




- In this approach we only launched the keyboard. But our aim was to handle the text typed in the keyboard and show it back to the editText on the status bar.

So for that instead of button we need to have a editText and launch the keyboard for this view (EditText ). and when the user presses 'Go' or 'Done' button get the text from this editText.

Will show you how to handle the button press on keyboard in coming blogs :)

Saturday, October 9, 2010

How to identify when lock screen is unlocked.?

My requirement was to listen for the intent when the screen is unlocked successfully.
Unfortunately, there is no such intent defined by Android framework, when the screen is unlocked successfully.

So i went into the framework code which takes care of showing lock screen, unlock screen and handling the events on that. It is present
/frameworks/policies/base/phone/com/android/internal/policy/impl

If in case you are working in framework level code and looking for the exact place in the code, here it is.

KeyguardViewMediator.java

Line no 801:
Here i have written code, to notify the Notification service, when the screen is unlocked. It works fine.



public void keyguardDone(boolean authenticated, boolean wakeup) {
synchronized (this) {
EventLog.writeEvent(70000, 2);
if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")");
System.out.println("Keygaurd screen unlocked ");
mManager.notify("SCREEN_UNLOCKED"); // The code i added.
Message msg = mHandler.obtainMessage(KEYGUARD_DONE);
msg.arg1 = wakeup ? 1 : 0;
mHandler.sendMessage(msg);

if (authenticated) {
mUpdateMonitor.clearFailedAttempts();
}

if (mExitSecureCallback != null) {
mExitSecureCallback.onKeyguardExitResult(authenticated);
mExitSecureCallback = null;

if (authenticated) {
// after succesfully exiting securely, no need to reshow
// the keyguard when they've released the lock
mExternallyEnabled = true;
mNeedToReshowWhenReenabled = false;
}
}
}
}



There are intents for when the screen is ON & OFF, but you can use that for screen unlocking.

- ACTION_SCREEN_ON
- ACTION_SCREEN_OFF.

I found in one of the forums which suggesting in round other way.

- Wait for ACTION_SCREEN_ON.
- (After screen is on,) Wait for ACTION_MAIN with category CATEGORY_HOME (Which launches the home screen) - This is probably what is sent after the phone gets unlocked.

Not sure this works. !! Check it out.

Monday, September 27, 2010

PhonewindowManager - Some details.

Some details and information i would like to share about some framework related on window managers, phone window managers. It might be a insight to dig more by first come learners .. !!

The three important managers interlinked for an application to be displayed are

– Window manager

(frameworks/base/services/java/com/android/server/WindowManagerService.java)
(frameworks/base/core/java/android/view/WindowManager.java)

– Surface manager / Surface flinger

(frameworks/base/libs/surfacelinger)

–Activity manager

(frameworks/base/services/java/com/android/server/am/ActivityManagerService.java)


All the three are started as thread by main proc “SystemServer”, when the system starts.

Window manager

– Asks the surface manager to create layout surfaces on behalf of client application.

– Dispatches input events to client.

– Transitions animations

[ The window manager creates surfaces for the application, and applications draw directly into those surfaces without going through the window manager.]

Surface manager

– Allocates surfaces ( means creation of memory,front end, back end buffers for application to draw its layout ).

– Interacts with OpenGL.

Activity Manager

– Manages life cycles of activities, stacking of activities.

– Takes care of intent dispatching.

There are two window manager implemented one for phone (phoneWindow manager) and another for mid (midWindow manager which is obselete now).

Window - Is a abstract base class for a top-level window look and behavior policy. An instance of this class should be used as the top-level view added to the window manager. It provides standard UI policies such as a background, title area, default key processing, etc.

The only existing implementation of this abstract class is android.policy.PhoneWindow, which you should instantiate when needing a Window.So it is designed like when an application is started, the activity manager(ActivityThread main loop ) gets the handle and requests creation of a PhoneWindow for the application on which the application's layouts will be drawn with the surface manager as said earlier.



The instantiation of PhoneWindow is provided in /frameworks/policies/base/phone/com/android/internal/policy.java file.

public PhoneWindow makeNewWindow(Context context) {
return new PhoneWindow(context);
}

public PhoneLayoutInflater makeNewLayoutInflater(Context context) {
return new PhoneLayoutInflater(context);
}

public PhoneWindowManager makeNewWindowManager() {
return new PhoneWindowManager();
}



When the window manager is started by SystemServer, it instantiates the deamon kind of thread named 'PhoneWindowManager ' which manages each 'phoneWindow'.What are the activities it manages and for phoneWindow ?

– Starts the power manager intially when the window manager instantiates this class.

– Intercepts / Handles the keys like Home,Back,Menu,Search, Keyguard, Media Key up and down. All these keys will be given to each PhoneWindow. So all the interactions on these keys will be handled here.

– Long press of Home button shows Recent apps dialog.

– Behavior of the power button,long press on KeyGaurd shows this dialog.

– Behavior of how to handle END_BUTTON_BEHAVIOR(Call button),INCALL_POWER_BUTTON_BEHAVIOR,ACCELEROMETER_ROTATION,SCREEN_OFF_TIMEOUT,DEFAULT_INPUT_METHOD . Basically it registers for the above contentRegister URIs.

– Adds the startingWindow ( a phoneWindow ) for an application. Basically to this window object,views are added to display the content.



public View addStartingWindow(IBinder appToken, String packageName, int theme, CharSequence nonLocalizedLabel,
int labelRes, int icon) {
Window win = PolicyManager.makeNewWindow(context); --> lin 867
----------------------
win.getDecorView(); --> Asks the 'PhoneWindow' to get the view
}


When an application is started, activity manager and window manager handles creation of 'PhoneWindow'. I havenot figured out why two windows are created.


1- Created by WindowManager (PhoneWindowManager ) :
------------------------------------------------------


I/ActivityManager( 60): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.HelloWorld/.HelloWorld }
V/PhoneWindowManager( 60): addStartingWindow com.android.HelloWorld: nonLocalizedLabel=null theme=0
D/dalvikvm( 60): GC_FOR_MALLOC freed 10917 objects / 494680 bytes in 133ms
I/PhonePolicy( 60): Making new Phone Window
I/PhonePolicy( 60): java.lang.RuntimeException
I/PhonePolicy( 60): at com.android.internal.policy.impl.Policy.makeNewWindow(Policy.java:59)
I/PhonePolicy( 60): at com.android.internal.policy.impl.Policy.makeNewWindow(Policy.java:33)
I/PhonePolicy( 60): at com.android.internal.policy.PolicyManager.makeNewWindow(PolicyManager.java:58)
I/PhonePolicy( 60): at com.android.internal.policy.impl.PhoneWindowManager.addStartingWindow(PhoneWindowManager.java:867)
I/PhonePolicy( 60): at com.android.server.WindowManagerService$H.handleMessage(WindowManagerService.java:9007)
I/PhonePolicy( 60): at android.os.Handler.dispatchMessage(Handler.java:99)
I/PhonePolicy( 60): at android.os.Looper.loop(Looper.java:123)
I/PhonePolicy( 60): at com.android.server.WindowManagerService$WMThread.run(WindowManagerService.java:570)


2 – Activity manager asks for a new PhoneWindow.
---------------------------------------------------


I/PhonePolicy( 279): Making new Phone Window
I/PhonePolicy( 279): java.lang.RuntimeException
I/PhonePolicy( 279): at com.android.internal.policy.impl.Policy.makeNewWindow(Policy.java:59)
I/PhonePolicy( 279): at com.android.internal.policy.impl.Policy.makeNewWindow(Policy.java:33)
I/PhonePolicy( 279): at com.android.internal.policy.PolicyManager.makeNewWindow(PolicyManager.java:58)
I/PhonePolicy( 279): at android.app.Activity.attach(Activity.java:3746)
I/PhonePolicy( 279): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2610)
I/PhonePolicy( 279): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
I/PhonePolicy( 279): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
I/PhonePolicy( 279): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
I/PhonePolicy( 279): at android.os.Handler.dispatchMessage(Handler.java:99)
I/PhonePolicy( 279): at android.os.Looper.loop(Looper.java:123)
I/PhonePolicy( 279): at android.app.ActivityThread.main(ActivityThread.java:4627)
I/PhonePolicy( 279): at java.lang.reflect.Method.invokeNative(Native Method)
I/PhonePolicy( 279): at java.lang.reflect.Method.invoke(Method.java:521)
I/PhonePolicy( 279): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
I/PhonePolicy( 279): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
I/PhonePolicy( 279): at dalvik.system.NativeStart.main(Native Method)


setContentView()

– Whenever an setContentView() is called in application's main activity, it will be given to PhoneWindow instance to create the view and display it.At this point, window manager talk to surface manager to draw the layouts on to the Window. This fundamental is common for all applications in Android.



public class HelloWorld extends Activity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}





V/PhoneWindow( 279): Phonewindow generateLayout
V/PhoneWindow( 279): java.lang.RuntimeException
V/PhoneWindow( 279): at com.android.internal.policy.impl.PhoneWindow.generateLayout(PhoneWindow.java:2058)
V/PhoneWindow( 279): at com.android.internal.policy.impl.PhoneWindow.installDecor(PhoneWindow.java:2234)
V/PhoneWindow( 279): at com.android.internal.policy.impl. PhoneWindow.setContentView(PhoneWindow.java:200)
V/PhoneWindow( 279): at android.app.Activity.setContentView(Activity.java:1647)
V/PhoneWindow( 279): at com.android.HelloWorld.HelloWorld.onCreate(HelloWorld.java:13)
V/PhoneWindow( 279): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
V/PhoneWindow( 279): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
V/PhoneWindow( 279): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
V/PhoneWindow( 279): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
V/PhoneWindow( 279): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
V/PhoneWindow( 279): at android.os.Handler.dispatchMessage(Handler.java:99)
V/PhoneWindow( 279): at android.os.Looper.loop(Looper.java:123)
V/PhoneWindow( 279): at android.app.ActivityThread.main(ActivityThread.java:4627)
V/PhoneWindow( 279): at java.lang.reflect.Method.invokeNative(Native Method)
V/PhoneWindow( 279): at java.lang.reflect.Method.invoke(Method.java:521)
V/PhoneWindow( 279): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
V/PhoneWindow( 279): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
V/PhoneWindow( 279): at dalvik.system.NativeStart.main(Native Method)



PhoneWindowManager and PhoneWindow – Plays a major role in framework to display the content of view, talk to surface manager and handles common utilities which a window ( in otherwords an application) can get. Like, menu,back, call, media keys handling.

There many ways we can set a View to an activity. One way is to create a LinearLayout?FrameLayout add it to a ViewGroup then add the ViewGroup to Window to display it. This is followed in showing Lock screen.

The hierarchy between them is as follows,

onCreate()
Activty --------------------------> Window
|
setContentView(View v, LayoutParams p) - Set a view to a Window.

View --> ViewGroup --> LinearLayout/FrameLayout.
|
|
|
addview(View , LayoutParams ) ( This is inherited to all subclasses )



Example to explain:
------------------------------


public class HelloWorld extends Activity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
View v = new MyLinearLayoutView(this);
setContentView(v);
}

}

public class MyLinearLayoutView extends LinearLayout
{
public MyLinearLayoutView(Context context)
{
super(context);
this.setOrientation(LinearLayout.VERTICAL);

\ TextView welcome = new TextView(context);
welcome.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
welcome.setText("Welcome screen");

TextView content = new TextView(context);
content.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
content.setText("This is a LinearLayout");

LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
this.addView(welcome,params);
this.addView(content,params);
}
}


If you dont specify the LayoutParams the default will be set as
new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT);

This is the same methodology which will be followed in the flow of creating LockScreen,UnlockScreen. In this way, to the 'PhoneWindow' instance addView( is used to set the content for the window ).