Pages:  1 2 ... 11 12 13 14 15 ... 21 22
lytsing – Page 13 – lytsing's Blog

Author: lytsing

  • 关于 android RIL 调试

    首先,要了解RIL是如何启动的,拿G1做个例子

    init.rc:

    service ril-daemon /system/bin/rild
        socket rild stream 660 root radio
        socket rild-debug stream 660 radio system
        user root
        group radio cache inet misc audio

    /system/build.prop:

    ro.ril.hsxpa=1
    ro.ril.gprsclass=10
    rild.libpath=/system/lib/libhtc_ril.so

    阅读 /hardware/ril/rild/rild.c。

    如果/system/bin/rild 启动有带参数,则解析参数,否则找系统变量 rild.libpath

    也可以不按照G1的,一口气写完:
    init.rc:
    /system/bin/rild -l /system/lib/libreference-ril.so — -d /dev/ttyS0

    /hardware/ril/rild/rild.c 里有一段注释: “special override when in the emulator”, 紧接着是 #if 1 … #endif 代码块。
    它读取 /proc/cmdline,

    # cat /proc/cmdline ,模拟器上的值
    qemu=1 console=ttyS0 android.checkjni=1 android.qemud=ttyS1 android.ndns=2

    找到与字符串“android.qemud“匹配的,则表示运行在模拟器上,会覆盖ril系统设置,连接为模拟器准备的 /dev/socket/qemud

    所以,在开发生产版本,要把 #if 1 修改为 #if 0, 或者在编译kernel里把生成的 /proc/cmdline 配置去掉android.qemud。

    要调试 RIL,最好的方法就是打开 radio的log:

    $ adb logcat -b radio

    最好加上 log语法亮度工具 coloredlogcat.py,一些常见的LOG TAG要明白,他们是:

    RIL: /hardware/ril/reference-ril/refereince-ril.c
    AT: /hardware/ril/reference-ril/atchannel.c
    RILD: /hardware/ril/rild/rild.c
    RILC: /hardware/ril/libril/ril.cpp
    RILB frameworks/base/telephony/java/com/android/internal/telephony/BaseCommands.java
    RILJ: /frameworks/base/telephony/java/com/android/internal/telephony/gsm/RIL.java
    GSM: /frameworks/base/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java

    如何在模拟器上外接 gsm modem?

    请参考 http://i-miss-erin.blogspot.com/2009/09/android-emulator-external-gsm-modem.html

  • PhoneFactory.getDefaultPhone must be called from Looper thread

    写了一个设置、显示本机号码的小工具(A small tool displays and settings my phone number),详见”Android设置显示本机号码“。照着Settings写的,运行时,遇到了:
    1487 AndroidRuntime E Caused by: java.lang.RuntimeException: PhoneFactory.getDefaultPhone must be called from Looper thread
    1487 AndroidRuntime E at com.android.internal.telephony.PhoneFactory.getDefaultPhone(PhoneFactory.java:155)
    1487 AndroidRuntime E ... 24 more

    目前好像除了PhoneApp,其他应用程序是无法调用
    com.android.internal.telephony.Phone;
    com.android.internal.telephony.PhoneFactory
    的,一般是通过发intent消息。仔细对比了一下,发现Settings的AndroidManifest.xml用到Phone的Activity属性添加了:

    android:process="com.android.phone"

    在AndroidManifest.xml 把android:sharedUserId=”android.uid.system”也加上,问题解决。像CM的固件, 编译的时候,android.uid.system 是 Android 默认的公共签名。如果使用android.uid.system的apk签名不不一样,是不能装的,会报错:ERROR/PackageManager(81): Package org.lytsing.myphonenumber has no signatures that match those in shared user android.uid.system; ignoring!

    当然,android手机第三方开发者不能用这个方法。网上还有其他一些解决办法,参看:
    http://stackoverflow.com/questions/2143754/can-a-telephony-phone-object-be-instantiated-through-the-sdk 原理是通过AIDL及反射机制,使用隐藏API。

  • Android 组件: SectionedAdapter

    这个组件与Mark Murphy 的书《The Busy Coder’s Guide to Advanced Android Development》有一些不同,这个SectionedAdapter是通过干坏事,反编译Vending.apk得到的。还有一个是AggregatedAdapter,合起来实现market单个软件信息显示的效果。
    android market asset info

    不过AggregatedAdapter比较难反编译出来,没关系,加上cwac-merge这个组件,就可以实现同样的效果。不同分段的Adapter,继承SectionedAdapter,实现自己的东西,该干啥就干啥,然后merge起来。

    SectionAdapter.java

    /*
     * Copyright (C) 2010 lytsing.org
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    
    package org.lytsing.adapters;
    
    import android.content.Context;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.TextView;
    
    /**
     * abstract SectionAdapter, difference from
     * cw-advandroid/ListView/Sections/src/com/commonsware/android/listview/SectionedAdapter.java
     * just decompile from Vending.apk :-)
     *
     */
    abstract public class SectionAdapter extends BaseAdapter {
        protected int mCount;
        protected boolean mDeactivated;
        protected View mSectionHeaderView;
    
        /**
         * Constructor
         * 
         * @param sectionTitleId The resource ID for a layout file containing a layout to use when
         *                  instantiating views.
         * @param context The current context.
         * @param parent The parent that this view will eventually be attached to
         */
        public SectionAdapter(int sectionTitleId, Context context, ViewGroup parent) {
            this(Util.inflateView(R.layout.section_header, context, parent));
            ((TextView)mSectionHeaderView).setText(sectionTitleId);
        }
    
        /**
         * Constructor
         * 
         * @param sectionHeaderView The header view
         */
        public SectionAdapter(View sectionHeaderView) {
            mSectionHeaderView = sectionHeaderView;
            mDeactivated = false;
            mCount = 0;
        }
    
        public void activate() {
            if (mDeactivated) {
                mDeactivated = false;
                notifyDataSetChanged();
            }
        }
    
        /**
         * Are all items in this SectionAdapter enable?
         * If yes it means all items are selectable and clickable.
         */
        public boolean areAllItemsEnabled() {
            return false;
        }
    
        public void deactivate() {
            if (mDeactivated == false) {
                mDeactivated = true;
                notifyDataSetChanged();
            }
        }
    
        /**
         * How many items are in the data set represented by this
         * Adapter.
         */
        public int getCount() {
            if (mDeactivated) {
                return 0;
            } else {
                return mCount + 1; // add one for header
            }
        }
    
        /**
         * Get the data item associated with the specified
         * position in the data set.
         * 
         * @param position Position of the item whose data we want
         */
        public Object getItem(int position) {
            if (position == 0) {
                return mSectionHeaderView;
            }
            
            return null;
        }
    
        /**
         * Get the row id associated with the specified position
         * in the list.
         * 
         * @param position Position of the item whose data we want
         */
        public long getItemId(int position) {
            if (position == 0) {
                return mSectionHeaderView.getId();
            } 
            
            return 0;
        }
    
        /**
         * Get a View that displays the data at the specified
         * position in the data set.
         * 
         * @param position Position of the item whose data we want
         * @param convertView View to recycle, if not null
         * @param parent ViewGroup containing the returned View
         */
        public View getView(int position, View convertView, ViewGroup parent) {
    
            return position == 0 ? mSectionHeaderView : null;
        }
    
        /**
         * Returns true if the item at the specified position is not a separator
         * (A separator is a non-selectable, non-clickable item).
         * 
         * @param position Index of the item
         * @return True if the item is not a separator
         */
        public boolean isEnabled(int position) {
            return false;
        }
    }

    Util.java

    /*
     * Copyright (C) 2010 lytsing.org
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.lytsing.adapters;
    
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    /**
     * Util 
     *
     */
    public class Util {
    
        private Util() {
        }
        
        /**
         * Inflate a new view hierarchy from the specified XML resource.
         * 
         * @param resource ID for an XML layout resource to load 
         * @param context The current context.
         * @return The root View of the inflated XML file.
         */
        public static View inflateView(int resource, Context context) {
    
            return inflateView(resource, context, null);
        }
    
        /**
         * Inflate a new view hierarchy from the specified xml resource.
         * 
         * @param resourceID for an XML layout resource to load (e.g.,
         * @param context The current context.
         * @param parent simply an object that provides a set of LayoutParams
         *        values for root of the returned hierarchy
         * @return The root View of the inflated XML file.
         */
        public static View inflateView(int resource, Context context, ViewGroup parent) {
            LayoutInflater vi = (LayoutInflater)context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    
            return  vi.inflate(resource, parent, false);
        }
    }

    res/layout/section_header.xml

    <?xml version="1.0" encoding="utf-8"?>
    <TextView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textStyle="bold"
        android:gravity="center_vertical"
        android:background="@android:drawable/dark_header"
        android:paddingLeft="8.0dip"
        android:layout_width="fill_parent"
        android:layout_height="26.0dip"
        >
    </TextView>
    

    代码下载; https://github.com/lytsing/SectionedAdapter
    参考阅读:
    Jeff Sharkey’s blog : Separating Lists with Headers in Android 0.9
    androidguys: CWAC’d Up: Alternative Adapters
    本博客文章: 千万不要把Listview放在ScrollView里

  • Bluehost没法安装mod_python

    $ httpd -l
    发现没装上 mod_python,网上搜一下,没找到有用的东西,于是给bluehost提交了一个ticket,希望他们能帮我装上。不多久就得到回复了:

    Hello,
    Thank you for choosing Bluehost. I understand you wish to use an apache module for Python. Unfortunately we do not offer mod_python and since it requires a recompile of apache we will be unable to implement it for you.

    看样子是需要把之前写的程序改为CGI了。

  • mysql将latin1编码更换为utf-8编码

    同事反馈,我们下载软件页面出现了乱码,抽个时间查看一下。我们在bluehost服务器数据库原来是mysql4,换到新的服务器上,安装的是mysql5,这样mysql4 默认的latin1编码显示就出现了乱码。

    搜索一下,网上盛传的一篇文章是《Mysql latin1编码转UTF8的方法
    试了许久,不成功,继续搜,发现这《mysql移置之将latin1编码更换为utf-8编码》 解决了,解说的比较到位。
    这文章后面导入的是gbk,我们的服务器需要是utf8,于是,总的就是输入三条命令:

    mysqldump --default-character-set=latin1 --create-options=false --set-charset=false -u root -p 数据库名 > market.sql
    create database 数据库名 CHARACTER SET utf8 COLLATE utf8_general_ci;
    mysql -u root -p --default-character-set=utf8 数据库名 < ~/数据库名.sql

    问题解决了。