2013年8月28日 星期三

[Hi3716c] Fix IR power key wake up mechanism

Some files worth noticing...
* device/hisilicon/godbox/driver/sdk/msp/ecs/drv/ir/ir_s2/ir_drv.c
IR driver. It handles IRQ.

* device/hisilicon/godbox/driver/sdk/msp_base/ecs/drv/include/ir.h
 IRQ no of IR is defined here

* kernel/arch/arm/mach-godbox/include/mach/irqs.h
Some IRQs are defined here

* device/hisilicon/godbox/driver/sdk/msp/ecs/drv/ir/ir_s2/hiir_ir2.h
Handles raw-linux_key_code mapping and works as API for the IR driver

* device/hisilicon/godbox/driver/sdk/sample/pmoc/sample_pmoc.c
A sample code to test IR and other ways to wake up the device

* device/hisilicon/godbox/driver/sdk/msp/ecs/drv/c51/drv_c51.c
MCU driver. MCU handles wake-up job after cpu power is down. The IR module decodes the infrared signals and then sends interrupts to MCU

* device/hisilicon/godbox/driver/sdk/msp/ecs/api/hi_unf_pm.c
A wrapped API to access MCU driver

* framework/base/core/jni/standby_wakeup.c
Hooked to the underlying HI_UNF_PM MCU driver wrapper APIs. It actually sets wake-up mode a particular power key code

* framework/base/service/jni/com_android_server_AlarmManagerService.cpp
android_server_AlarmManagerService_setWakeUp() body is here, which calls HI_Standby_Wakeup() in standby_wakeup.c

* framework/base/service/jni/com_android_server_PowerManagerService.cpp
android_server_PowerManagerService_nativeSetWakeup() body is here, which calls  android_server_AlarmManagerService_setWakeUp() in com_android_server_AlarmManagerService.cpp

* framework/base/services/java/com/android/server/PowerManagerService.java
goToSleep() body is here, which calls nativeSetWakeup() defined in com_android_server_PowerManagerService.cpp, which points to  android_server_PowerManagerService_nativeSetWakeup()

What happens when a power key is detected for standby mode to proceed to set the wake-up key attribute from the point of view of Android:

interceptKeyBeforeQueueing(), frameworks/base/services/jni/com_android_server_InputManager.cpp
 |
V
interceptKeyBeforeQueueing(), frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
 |
V
handleInterceptActions(), frameworks/base/services/jni/com_android_server_InputManager.cpp
 |
V
goToSleep(), framework/base/services/java/com/android/server/PowerManagerService.java
 |
V
nativeSetWakeup(),  framework/base/service/jni/com_android_server_PowerManagerService.cpp
 |
V
android_server_AlarmManagerService_setWakeUp(),  framework/base/service/jni/com_android_server_AlarmManagerService.cpp
 |
V
HI_Standby_Wakeup(),  framework/base/core/jni/standby_wakeup.c

Related shell commands...
* Trigger standby mode
echo MODE > /sys/power/state
MODE: on, standby, mem

* Test standby/wakeup functions
sample_pmoc

The fix:
Modify the wake-up value from 0x639cff00 to 0xfd024db2 in  HI_Standby_Wakeup().


2013年8月23日 星期五

Store perminant data in Android

There are basically 3 ways to save data in Android. The one I'm going to talk about here is SharedPreferences method. Before expanding the usage, be aware of that  SharedPreferences method does not apply across multiple processes.The following is the snippet:

import android.content.SharedPreferences;
...
private SharedPreferences mKeyAppMap;
...
mKeyAppMap = mContext.getSharedPreferences(HOTKEY_PREF_NAME, 0);
...
String AppName = mKeyAppMap.getString(targetName,"none"); <-- Get data
...

SharedPreferences.Editor editor = mKeyAppMap.edit(); <-- Save data

editor.putString(key, appName);
editor.commit();

Reference links
http://www.ozzysun.com/2010/11/android.html
http://developer.android.com/training/basics/data-storage/index.html

Implementing Broadcasting in Android

The snippet:
---------------------------- Receiver body --------------------------------------------
private String ACTION_CUSTOM_HOTKEY = "android.internal.policy.impl.PhoneWindowManager";

BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
...
            else if (ACTION_CUSTOM_HOTKEY.equals(intent.getAction())) {
                String key = intent.getExtras().getString("whichkey");
                String appName = intent.getExtras().getString(key);
                Log.d(TAG, "write pair " + key + "-" + appName);
                SharedPreferences.Editor editor = mKeyAppMap.edit();
                editor.putString(key, appName);
                editor.commit();
            }
 ...
    };

---------------------------- Register the receiver and filter ----------------------------
IntentFilter filter = new IntentFilter();
...

filter.addAction(ACTION_CUSTOM_HOTKEY);
Intent intent = context.registerReceiver(mDockReceiver, filter);
if (intent != null) {
       // Retrieve current sticky dock event broadcast.
       mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
               Intent.EXTRA_DOCK_STATE_UNDOCKED);

}
...
-----------------------------------------------------------------------------------
Instead of using registerReceiver, one could also add the filter it in the manifest file for permitted intent action.
-----------------------------------------------------------------------------------
----------------------- Send broadcasting message -------------------------------
Intent intent = new Intent();
intent.setAction("android.internal.policy.impl.PhoneWindowManager");
intent.putExtra("whichkey", currentTab);
intent.putExtra(currentTab, entry.info.packageName);
getActivity().sendBroadcast(intent);

Reference links
http://stackoverflow.com/questions/3907713/how-to-send-and-receive-broadcast-message
http://www.techotopia.com/index.php/Android_Broadcast_Intents_and_Broadcast_Receivers
http://www.ozzysun.com/2010/11/android.html

2013年8月19日 星期一

[Code trace] Android Irda input key mapping


[Irda key mapping to Anroid layer]
Take color key, red, as the example to illustrate the flow to add a new key
==================================================================
- device/hisilicon/godbox/driver/sdk/msp/ecs/drv/ir/ir_s2/hiir_ir2.h
Obtain the keycode of red key and define a MACRO as below:
#define NEC_IR_KEY_RED                                  0xcd
...
Maps Irda keycode to keylabel RED 398:
{NEC_IR_KEY_RED,     KEY_RED},
-------------------------------------------------------------------------------------------
- device/hisilicon/godbox/prebuilt/Vendor_0001_Product_0001.kl
key 398         RED
# key 398 "KEY_RED"
-------------------------------------------------------------------------------------------
211 is the event value retrieved through onKeyDown() in Android.

- external/webkit/Source/WebKit/android/plugins/ANPKeyCodes.h
kRed_ANPKeyCode = 211,

- frameworks/base/native/include/android/keycodes.h
AKEYCODE_RED = 211,

- frameworks/base/core/java/android/view/KeyEvent.java
public static final int KEYCODE_RED     = 211;

- frameworks/base/core/res/res/values/attrs.xml
<enum name="KEYCODE_RED" value="211" />
-------------------------------------------------------------------------------------------
- frameworks/base/include/ui/KeycodeLabels.h
Maps keylabel RED 398 to 211
{ "RED", 211 },
-------------------------------------------------------------------------------------------
- frameworks/base/libs/ui/Input.cpp
case AKEYCODE_RED:

[Code trace] power management (standby/suspend/resume) mechanism in Android & Linux

[INPUT MNGR]
frameworks/base/services/jni/com_android_server_InputManager.cpp
NativeInputManager::handleInterceptActions() :
dispatch keys to users or filter them as special event key like power control...

handleInterceptActions() callbacks to PowerManagerService goToSleep() for putting to sleep, to another function to wake it up, or passing keys to users

Code flow:
interceptKeyBeforeQueueing(), frameworks/base/services/jni/com_android_server_InputManager.cpp
 |
V
interceptKeyBeforeQueueing(), frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
 |
V
handleInterceptActions(), frameworks/base/services/jni/com_android_server_InputManager.cpp

[PWR MNGR CODE FLOW]
frameworks/base/core/java/android/os/PowerManager.java - API for APPS
 |
V
frameworks/base/services/java/com/android/server/PowerManagerService.java - core
 |
V
frameworks/base/core/java/android/os/Power.java - JNI


Reference links
http://blog.csdn.net/tommy_wxie/article/details/7208633
http://3y.uu456.com/bp-f823387031b76sce0s081439-1.html 

Very good illustration for the architecture of PM in Android
http://www.kandroid.org/online-pdk/guide/power_management.html

This is a very handy illustration on standby/wake framework from top to bottom
http://blog.csdn.net/lizhiguo0532/article/details/6453595

Tells different configuring opions for /sys/power/state
http://www.mjmwired.net/kernel/Documentation/power/states.txt


Start an APP from another APP in Android

The following is the snippet for testing:

import android.content.pm.ResolveInfo;
import java.util.List;


if (keyCode == KeyEvent.KEYCODE_GREEN) {
             Log.d(TAG, "green key is triggered");
             Intent hotkey_intent = new Intent("android.intent.action.MAIN");
             hotkey_intent.addCategory("android.intent.category.LAUNCHER");

             List<ResolveInfo> resolveinfo_list = mContext.getPackageManager().queryIntentActivities(hotkey_intent, 0);

             for(ResolveInfo info:resolveinfo_list){
                 Log.d(TAG, info.activityInfo.packageName);
                 if(info.activityInfo.packageName.equalsIgnoreCase("com.android.settings")){
                     hotkey_intent.setComponent(new ComponentName(info.activityInfo.packageName, info.activityInfo.name));
                     hotkey_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                     mContext.startActivity(hotkey_intent);
                     break;
                 }
             }
         }


settings APP is brought up when GREEN key is pressed.

Action and category seem to work as filters for the activities it searches. In order to get a full list of APPs, I perhaps have to change them.

Reference links
http://stackoverflow.com/questions/2780102/open-another-application-from-your-own-intent

[Code trace] Android Irda Input key handling

The purpose is to find out where some globally functioned keys are handled, like power key, which is specially handled within handleInterceptActions() after interceptKeyBeforeQueueing() is called, and a key works to change the TV display format wherever you are. The goal however, is to add a set of 4 hot keys each of which is a shortcut to a certain APP.

remote control key : UP
------------------------------------------------------------------------------------------------
D/InputReader( 1417): BatchSize: 2 Count: 2
D/InputReader( 1417): Input event: device=1 type=0x0001 scancode=0x0067 keycode=0x0013 value=0x00000001 flags=0x00000000
D/InputReader( 1417): Input event: device=1 type=0x0000 scancode=0x0000 keycode=0x0000 value=0x00000000 flags=0x00000000

D/WindowManager( 1417): UP key is pressed/released
D/KeyEvent-JNI( 1417): android_view_KeyEvent_recycle...
D/InputManager-JNI( 1417): NativeInputManager::handleInterceptActions
D/KeyEvent-JNI( 1417): android_view_KeyEvent_recycle...
D/KeyEvent-JNI( 1417): android_view_KeyEvent_recycle...

------------------------------------------------------------------------------------------------
                                 (1)                   (2)
remote control key <-> scancode <-> keycode
        0xca                        0x67              0x13

remote control key :  device/hisilicon/godbox/driver/sdk/msp/ecs/drv/ir/ir_s2/hiir_ir2.h
keycode :  frameworks/base/native/include/android/keycodes.h
scancode : device/hisilicon/godbox/prebuilt/Vendor_0001_Product_0001.kl

Mappings:
(1) device/hisilicon/godbox/driver/sdk/msp/ecs/drv/ir/ir_s2/hiir_ir2.h
(2) frameworks/base/include/ui/KeycodeLabels.h

The following code handles a universal key event - KEYCODE_MORE(0x498)
[Window Manager]
frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
interceptKeyBeforeQueueing()

After finding out the place, the idea is then to handle these 4 hot keys here in interceptKeyBeforeQueseing() and jump to the corresponding APP designated.

Reference links
http://www.hovercool.com/en/Special:History?topicVersionId=767&topic=Input%E4%BA%8B%E4%BB%B6%E6%B5%81%E7%A8%8B
http://blog.csdn.net/eastmoon502136/article/details/7697434

2013年8月5日 星期一

Javascript special semantics and common mistakes guide

http://bonsaiden.github.io/JavaScript-Garden/zhtw/#function.constructors

New local JS file which provides functions for external JS files to use

 JS file:

function atv() {}









atv.prototype = {
    ProxyDocument: function() {
        this.show = function() {};
        this.onCancel = function() {};
        this.loadXML = function(xmldoc, handler) {
            xmlText = new XMLSerializer().serializeToString(xmldoc);
            gtkTV.loadXML(gtkTV.parseXML(xmlText));
        };
    },
    loadXML: function(doc) {
        gtkTV.loadXML(doc);
    },
    parseXML: function(xml) {
        return gtkTV.parseXML(xml);
    },
    loadPlist: function(item) {      
        gtkTV.sponsor_play(item['media-asset']['media-url']);
    },
    onAppEntry: function() {},
    onAppExit: function() {},
    config: 0,
    localStorage: function() {
        this.getItem = function(key) {
            return this[key];
        };
        this.setItem = function(key, value) {
            this[key] = value;
        };
        this.SHOWTIMES_AVAIALABLE = 1;
    },
    sessionStorage: function() {
        this.getItem = function(key) {
            return this[key];
        };
        this.setItem = function(key, value) {
            this[key] = value;
        };
        this.DEBUG_LEVEL = 0;
    },
    player: function() {
        this.currentAssetChanged = 0;
        this.playerStateChanged = 0;
        this.willStartPlaying = 0;
        this.playerTimeDidChange = 0;
    },
    device: function() {
        this.udid = 'DY3HJY89DRHN';
        this.displayName = 'Gemtek';
    },
    Document: function() {},
    Element: function() {}
}

atv = new atv;
atv.sessionStorage = new atv.sessionStorage;
atv.localStorage = new atv.localStorage;


Javascript has no actual class identifier. We use function to achieve the similiar idea. In the code, atv.prototype defines the methods in the atv function. Javascript uses function to define a instance, and for the special use of declaration like "atv.sessionStorage", a nested function prototype needs to be defined within atv function. In order to use them, create them using new and it looks like same naming does not violate much of the Javascript semantics.

Reference links
http://blog.roodo.com/rocksaying/archives/18294075.html
http://repl.it/
http://bonsaiden.github.io/JavaScript-Garden/zhtw/#function.constructors
http://stackoverflow.com/questions/9898698/convert-xml-to-string-and-append-to-page

2013年8月4日 星期日

Use loadDataWithBaseURL()

Somehow loadDataWithBaseURL just works and loadData just does not work when I'm trying to load a local JS file and use defined structure from it.

Reference links
http://stackoverflow.com/questions/7848359/running-javascript-in-webview-when-using-loaddata

a new way to call a JS function from external JS files

The old way is that I create a basic html file containing local javascript code and load it using WebView.loadURL(). In order to call a JS function within an external JS file, I then set up a event handler as onPageFinished() for the WebView Client and call loadURL() which runs a piece of javascript code that include external JS files and call the JS function inside onload attribute of the script tag. However with this method I sometimes can not call the JS functions I need possibly because of the external JS files don't really loaded as I expect whether sequentially or completely, and local JS code does not seem to load at the right time when external JS file inclusion exists.

So now here is the new solution for this after a great deal of experiments.
(1) a very simple html file
(2) a local JS file seperate from the old html file
(3) Use loadDataWithBaseURL() insead of loadURL(). Load data which is the content of the simple html file with modification of adding desired external JS file inclusion and local JS file inclusion
(4) Set up onPageFinished event which only calls the JS function

The code:

        myWebView = new WebView(this);
        myWebView.getSettings().setJavaScriptEnabled(true);
        myWebView.getSettings().setBuiltInZoomControls(true);
        myWebView.getSettings().setUserAgentString("iTunes-AppleTV/5.1 (3; 8GB; dt:12)");
        if(android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
            myWebView.getSettings().setAllowUniversalAccessFromFileURLs(true);
        }
        myWebView.setWebChromeClient(new WebChromeClient());
       
        myWebView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                view.loadUrl("javascript:atv.onAppEntry();");
            }
        });
        myWebView.addJavascriptInterface(new MyAndroidJSInterface(this, MainActivity.class), "gtkTV");
        myWebView.loadDataWithBaseURL("file:///android_asset/", new commonUtility(this).addJSsrc2DOM("tmp.html", js_url),"text/html", null, null);


what's not to achieve the goal:
1. Use loadData() instead of loadDataWithBaseURL().
2. Mix inline script code with external JS files inclusion even in the order of correct dependencies.

Reference links
http://stackoverflow.com/questions/3961589/android-webview-and-loaddata
http://developer.android.com/reference/android/webkit/WebView.html
http://developer.android.com/reference/android/webkit/WebViewClient.html#onPageStarted%28android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap%29

2013年8月2日 星期五

Update a HTML file and convert it back from DOM to String

The target is to that while having a local html file and say you wanna update it with additional code like javascript and load it using WebView.loadDataWithBaseURL(). How are you going to do that ? The idea is to load the local file and transform it to DOM instance, and then you operate on the instance to modify the content, and finally you transform it back to a String instance.

The code snippet:

public String addJSsrc2DOM(String path, String js_url[]) {
        Document doc;
        String result;
       
        /* Convert to Document obj */
        String html_content = assetFile2Str(path);
        MyAndroidJSInterface obj = new MyAndroidJSInterface(mcontext, commonUtility.class);
        doc = obj.parseXML(html_content);
       
        for (int i = -2;;i++) {
            String target_js;
           
            if (i == -2) {
                target_js = "local.js";
            }
            else if (i == -1) {
                target_js = "http://trailers.apple.com/appletv/us/js/application.js";
            }
            else if (js_url[i] == null) {
                break;
            }
            else {
                target_js = js_url[i];
            }
           
            /* Create a script Element to contain JS src info */
            Element script = doc.createElement("script");
            script.setAttribute("type", "text/javascript");
            script.setAttribute("src", target_js);
            doc.getElementsByTagName("head").item(0).appendChild(script);
        }
        result = getStringFromDocument(doc);
        System.out.println(result);
        return result;
    }
   
    private String getStringFromDocument(Document doc)
    {
        try
        {
           DOMSource domSource = new DOMSource(doc);
           StringWriter writer = new StringWriter();
           StreamResult result = new StreamResult(writer);
           TransformerFactory tf = TransformerFactory.newInstance();
           Transformer transformer = tf.newTransformer();
           transformer.transform(domSource, result);
           return writer.toString();
        }
        catch(TransformerException ex)
        {
           ex.printStackTrace();
           return null;
        }
    }
   
    private String assetFile2Str(String path) {
        String str = "";
        try {
            InputStream is = mcontext.getAssets().open(path);
            int size = is.available();

            byte[] buffer = new byte[size];
            is.read(buffer);
            is.close();

            str = new String(buffer);
        }
        catch(IOException e) {}
        return str;
    }


Reference links
http://www.theserverside.com/discussions/thread.tss?thread_id=26060