Skip to content

Instantly share code, notes, and snippets.

@manniru
Created July 24, 2014 03:01
Show Gist options
  • Save manniru/a2eaed2ead2e7a2eb74c to your computer and use it in GitHub Desktop.
Save manniru/a2eaed2ead2e7a2eb74c to your computer and use it in GitHub Desktop.

TRANSITION

Why my list item doesn't remain selected

Imagine a simple application, ApiDemos for example, that shows a list of text items. The user can freely navigate
through the list using the trackball but also, alternatively, scroll and fling the list using the touch screen. The
issue in this scenario is how to handle the selection properly when the user manipulates the list through the touch
screen.

In this case, if the user selects an item at the top of the list and then flings the list towards the bottom, what
should happen to the selection? Should it remain on the item and scroll off the screen? What should happen if the user
then decided to move the selection with the trackball? Or worse, what should happen if the user presses the trackball to
act upon the currently selected item, which is not shown on screen anymore?

After careful consideration, we decided to remove the selection altogether, when the user manipulates the UI through the
touch screen.

In touch mode, there is no focus and no selection. Any selected item in a list of in a grid becomes unselected as soon
as the user enters touch mode. Similarly, any focused widgets become unfocused when the user enters touch mode. The
image below illustrates what happens when the user touches a list after selecting an item with the trackball.

Remember that a list item can be selected or choosen

UTILITY

MISCELLANEOUS

From terminal

# logcat

shows the android log.

Failed to set PTK to the driver
# modprobe ieee80211_crypt_tkip

Package bla.bla.bla has corrupt installation

$ adb shell cat /data/system/packages.list

SDCARD

It's the less speedy type of storage of the device.

The vold demon mounts the sdcard and it's configurated using the /etc/vold.fstab (older version uses vold.conf)

JAVA

BROWSER

Lifecycle

THREAD

Don't violate the single thread for the UI Painless threading

ANR

In case you are presented with a ANR dialog you can see in the logcat the following message

I/dalvikvm(  292): Wrote stack traces to '/data/anr/traces.txt'

Pull the file via adb and look at the stack trace.

If you use a spinning wheel as loading indication, keep attention that is actuallty animated, otherwise you are in the UI thread and you are not doing right the threading stuffs.

RESOURCES

GAPPS

STYLE

PORTING

DEBUGGING

LOW LEVEL

Launch an app from command line

$ adb shell am start -n org.ktln2.android.packt/.ActionBarActivity

BLOGROLL

BUGS

EMULATOR

It's possible to use buildroid to have a VirtualBox image with Google Apps that is more speedy respect to the qemu one.

In order to simulate a call in the cellphone

$ telnet localhost 5554 <<!
> gsm call 12345678
> !
// from http://dl.google.com/io/2009/pres/Th_0230_TurboChargeYourUI-HowtomakeyourAndroidUIfastandefficient.pdf
static class ViewHolder {
TextView text;
ImageView icon;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_icon_text, parent, false);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText(DATA[position]);
holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2);
return convertView;
}
$ hmm
Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment:
- lunch:   lunch <product_name>-<build_variant>
- tapas:   tapas [<App1> <App2> ...] [arm|x86|mips|armv5] [eng|userdebug|user]
- croot:   Changes directory to the top of the tree.
- m:       Makes from the top of the tree.
- mm:      Builds all of the modules in the current directory, but not their dependencies.
- mmm:     Builds all of the modules in the supplied directories, but not their dependencies.
           To limit the modules being built use the syntax: mmm dir/:target1,target2.
- mma:     Builds all of the modules in the current directory, and their dependencies.
- mmma:    Builds all of the modules in the supplied directories, and their dependencies.
- cgrep:   Greps on all local C/C++ files.
- jgrep:   Greps on all local Java files.
- resgrep: Greps on all local res/*.xml files.
- godir:   Go to the directory containing a file.

Look at the source to view more functions. The complete list is:
addcompletions add_lunch_combo cgrep check_product check_variant choosecombo chooseproduct choosetype choosevariant cproj croot findmakefile gdbclient gdbwrapper get_abs_build_var getbugreports get_build_var getdriver getlastscreenshot getprebuilt getscreenshotpath getsdcardpath gettargetarch gettop godir hmm is isviewserverstarted jgrep key_back key_home key_menu lunch _lunch m mangrep mm mma mmm mmma pez pid printconfig print_lunch_menu qpid resgrep runhat runtest sepgrep set_java_home setpaths set_sequence_number set_stuff_for_environment settitle smoketest stacks startviewserver stopviewserver systemstack tapas tracedmdump

http://www.jayway.com/2012/10/24/a-practical-approach-to-the-aosp-build-system/

LOCAL_MODULE is the variable defining a module to build, in order to find where is defined you can use the following piece command

find . ! -path './out/*' -name Android.mk -exec grep -H 'LOCAL_MODULE.*:=.*'<module name> \{\}  \;

First of all build/core/main.mk looks for all the Android.mk in the AOSP using the command

$ build/tools/findleaves.py --prune=out --prune=.repo --prune=.git . Android.mk

After that in build/core/product.mk the system build up the PRODUCT_MAKEFILES variable containing all the products available to build:

#
# Functions for including AndroidProducts.mk files
#

#
# Returns the list of all AndroidProducts.mk files.
# $(call ) isn't necessary.
#
define _find-android-products-files
$(shell test -d device && find device -maxdepth 6 -name AndroidProducts.mk) \
  $(shell test -d vendor && find vendor -maxdepth 6 -name AndroidProducts.mk) \
  $(SRC_TARGET_DIR)/product/AndroidProducts.mk
endef

#
# Returns the sorted concatenation of PRODUCT_MAKEFILES
# variables set in the given AndroidProducts.mk files.
# $(1): the list of AndroidProducts.mk files.
#
define get-product-makefiles
$(sort \
  $(foreach f,$(1), \
    $(eval PRODUCT_MAKEFILES :=) \
    $(eval LOCAL_DIR := $(patsubst %/,%,$(dir $(f)))) \
    $(eval include $(f)) \
    $(PRODUCT_MAKEFILES) \
   ) \
  $(eval PRODUCT_MAKEFILES :=) \
  $(eval LOCAL_DIR :=) \
 )
endef

#
# Returns the sorted concatenation of all PRODUCT_MAKEFILES
# variables set in all AndroidProducts.mk files.
# $(call ) isn't necessary.
#
define get-all-product-makefiles
$(call get-product-makefiles,$(_find-android-products-files))
endef

Inside build/target/board/Android.mk is called the AndroidBoard.mk of the target device by

-include $(TARGET_DEVICE_DIR)/AndroidBoard.mk

We have only to know that TARGET_DEVICE_DIR is defined as

# Boards may be defined under $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)
# or under vendor/*/$(TARGET_DEVICE).  Search in both places, but
# make sure only one exists.
# Real boards should always be associated with an OEM vendor.
board_config_mk := \
	$(strip $(wildcard \
		$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
		device/*/$(TARGET_DEVICE)/BoardConfig.mk \
		vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \
	))
ifeq ($(board_config_mk),)
  $(error No config file found for TARGET_DEVICE $(TARGET_DEVICE))
endif
ifneq ($(words $(board_config_mk)),1)
  $(error Multiple board config files for TARGET_DEVICE $(TARGET_DEVICE): $(board_config_mk))
endif

TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))

in build/core/config.mk. Instead in build/core/definitions.mk

# Copy a prebuilt file to a target location.
define transform-prebuilt-to-target
@echo "$(if $(PRIVATE_IS_HOST_MODULE),host,target) Prebuilt: $(PRIVATE_MODULE) ($@)"
$(copy-file-to-target)
endef
define copy-file-to-target
@mkdir -p $(dir $@)
$(hide) $(ACP) -fp $< $@
endef

From build/target/board/Android.mk

ifneq ($(strip $(TARGET_NO_KERNEL)),true)
  INSTALLED_KERNEL_TARGET := $(PRODUCT_OUT)/kernel
else
  INSTALLED_KERNEL_TARGET :=
endif

Recovery&Update.zip

It's possible to update the system using a zip file containing a script. For the code about this functionality look at the code.

Fastboot

It's not possible to use it with the emulator (source).

https://android.googlesource.com/platform/system/core/+/android-4.2.2_r1.2/fastboot/fastboot.c

Toolchains

A=$ANDROID_BUILD_TOP
TC=/tmp/toolchain-source
cd $A/ndk/build/tools
./download-toolchain-sources.sh $TC


mkdir -p /opt/android-toolchain-repo/
cd /opt/android-toolchain-repo
repo init -u https://android.googlesource.com/toolchain/manifest.git
repo sync
Obtain info about an APK
$ aapt dump badging <application.apk>
Obtain the certificate of the given apk
$ unzip -l <application.apk> | awk '/RSA/{print $4}'
$ unzip -p <application.apk> /META-INF/X.RSA | keytool -printcert
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;
import java.io.IOException;
/**
*
* Inspired by <http://stackoverflow.com/questions/9327053/using-custom-font-in-android-textview-using-xml>
*
*/
public class CustomeFontTextView extends TextView {
final static String TAG = "TNTTextView";
public TNTTextView(Context context) {
super(context);
init(context);
}
public TNTTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public TNTTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
protected void init(Context context) {
if (isInEditMode())
return;
setPaintFlags(getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
Typeface typeface = Typeface.createFromAsset(context.getAssets(), "fonts/gilli_sans_light.TTF");
setTypeface(typeface);
}
}

Layout inflating

import android.view.LayoutInflater;

  LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  View view = inflater.inflate(R.layout.my_layout, null);

oppure

 LayoutInflater inflater = getActivity().getLayoutInflater();
 

Programmatically set Layout parameters

ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
 

Prigrammatically change view dimension

    // http://stackoverflow.com/questions/2963152/android-how-to-resize-a-custom-view-programmatically
    ViewGroup.LayoutParams lp = parent.getLayoutParams();
    lp.height = 2000;
    parent.setLayoutParams(lp);

Activity starting

source

public void startRicettarioActivity(View view) {
    Intent i = new Intent(this, RicettarioActivity.class);
    
    i.putExtra("miao", 5);

    startActivity(i);
}

Start navigator

                // see http://stackoverflow.com/questions/16459426/android-navigation-intent
                Uri routeUri = Uri.parse("http://maps.google.com/maps?&saddr=" +
                        mLocationClient.getLastLocation().getLatitude() + "," +
                        mLocationClient.getLastLocation().getLongitude() + "&daddr=" + depot.town +", " + depot.address);

                Intent i = new Intent(Intent.ACTION_VIEW, routeUri);
                startActivity(i);

Retrieve parameters

public void onCreate(Bundle savedInstanceState) {
	getIntent().getExtras().getInt("miao");
}

Click programatically on list item

Take in mind that the getChildAt() argument must take into account the getFirstVisiblePosition()

            final int last = mListView.getCount() - 1;

            mListView.performItemClick(
                    mListView.getChildAt(last),
                    last,
                    mListView.getItemIdAtPosition(last));

Filter an Adapter

in the Fragment/Activity containing the ListView/Adapter

    // this enables the filtering capabilities
    mListView.setTextFilterEnabled(true);
    // pass to the detail when an item is clicked
            ((EditText)getActivity().findViewById(R.id.search_box))
            .addTextChangedListener(new TextWatcher() {

                public void afterTextChanged(Editable s) {
                }

                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                }

                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    android.util.Log.d(TAG, "filter with " + s);
                    // strange enough, if we use mAdapter raise NullPointerException
                    SimpleCursorAdapter adapter = (SimpleCursorAdapter)mListView.getAdapter();
                    adapter.getFilter().filter(s);
                    adapter.notifyDataSetChanged();
                }
            });

In the adapter

        setFilterQueryProvider(new FilterQueryProvider() {
            @Override
            public Cursor runQuery(CharSequence charSequence) {
                android.util.Log.d(TAG, "runQuery(): " + charSequence);
                return new DatabaseMeta(getActivity()).getFilteredRicettario(charSequence.toString());
            }
        });

Show/Hide keyboard

        InputMethodManager inputManager = (InputMethodManager)
                getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
        inputManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(),
                InputMethodManager.HIDE_NOT_ALWAYS);

Create preferences

package com.example.android;

import android.preference.PreferenceActivity;
import android.os.Bundle;


public class Preference extends PreferenceActivity {
	@Override
	public void onCreate(Bundle b) {
		super.onCreate(b);

                // so we link this preferences with this name
                // and we can edit that with SharedPreferences.Editor instance
		getPreferenceManager()
			.setSharedPreferencesName(MyApplication.PREFS_NAME);
		addPreferencesFromResource(R.xml.preferences);
	}
}

Fix orientation to portrait

<application
       ...
       >
       <activity android:name=".HomeActivity"
                  android:label="@string/app_name"
                  android:screenOrientation="portrait"
                  />

Copy data from clipboard

    /**
     * @return the first item in the clipboard
     *
     * http://stackoverflow.com/questions/14189544/copy-with-clipboard-manager-that-supports-old-and-new-android-versions
     */
    private CharSequence getClipboardContent() {
        int sdk = android.os.Build.VERSION.SDK_INT;
        if(sdk < android.os.Build.VERSION_CODES.HONEYCOMB) {
            android.text.ClipboardManager clipboard = (android.text.ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
            return clipboard.getText();
        } else {
            android.content.ClipboardManager clipboard = (android.content.ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
            ClipData data = clipboard.getPrimaryClip();
            if (data == null)
                return null;
            return data.getItemAt(0).getText();
        }
    }

Add a telephone number in android contacts not associated with any account on the telephone

ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();

ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
		/*
		 * ACCOUNT_TYPE
		 *
		 * The type of account to which this row belongs, which when paired with ACCOUNT_NAME
		 * identifies a specific account. It should be set at the time the raw contact is
		 * inserted and never changed afterwards.
		 * 
		 * To ensure uniqueness, new account types should be chosen according to the Java
		 * package naming convention. Thus a Google account is of type "com.google".
		 */
				.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)// null to create an unassociated one
				.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
				.build());


		ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
				.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
				.withValue(ContactsContract.Data.MIMETYPE,
					ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
				.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, whatever)
				.build());

		ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
				.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
				.withValue(ContactsContract.Data.MIMETYPE,
					ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
				.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, mTelephone)
				.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, Contacts.Phones.TYPE_MOBILE)
				.build());
		ContentProviderResult[] cprs = getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);

Enable javascript and Flash in an Android WebView

        WebView wv = (WebView)findViewById(R.id.webViewId);
        wv.getSettings().setJavaScriptEnabled(true);
        wv.getSettings().setPluginsEnabled(true);

webview that handles fixed credentials for authentication

        WebView wv = (WebView)findViewById(R.id.webViewId);

        wv.setWebViewClient(new WebViewClient() {
                public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                        Toast.makeText(EmbedActivity.this, "Oh no! " + description, Toast.LENGTH_SHORT).show();
                }

                public void onReceivedHttpAuthRequest(WebView webView, HttpAuthHandler handler, String host, String realm) {
                        handler.proceed("username", "password");
                }
        });

        wv.loadUrl("http://www.example.com/");

Avoid the webview to scroll when inside a scroll view

/**
 * Inserts into a WebView the htmlContent passed as argument.
 *
 * <b>NOTE:</b> the move touch events are removed.
 */
static public void insertHTML(WebView wv, String htmlContent) {
	 wv.setOnTouchListener(new View.OnTouchListener() {
		public boolean onTouch(View v, MotionEvent event) {
			 return (event.getAction() == MotionEvent.ACTION_MOVE);
		}
	});
	wv.loadData(htmlContent, "text/html", "UTF-8");
}

Retrieve UUID

http://blog.vogella.com/2011/04/11/android-unique-identifier/

Cyanogenmod allows to build for your device an Android distribution; in most cases however the official repository doesn't contain your device so you must download from another repository with its manifest.

If you don't want to re-download all the things but using the previous donwloaded code, you can use a separate manifest from that repository saving it in a temporary location and using it with repo sync and its -m option (using a absolute path to it).

For example in the following commands we use the repository for the motorola

$ wget https://raw.github.com/kfazz/android/jellybean/default.xml -O .repo/motorola_sholes.xml
$ repo sync -m .repo/motorola_sholes.xml -j 6

Links

HUAWEI8800pro

Holding Volume up and Volume down while power on the phone, a pink screen will appear; if you connect the cellphone to your computer with the mini usb cable you can access the partitions like an usb key.

Holding Volume up and power instead you can access the recovery.

If you want to compile cyanogenmod, this is the local_manifest.xml used by me


<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <project name="Blefish/android_device_huawei_u8800/" path="device/huawei/u8800" remote="github" revision="cm-10.1" />
  <project name="Blefish/android_vendor_huawei_u8800/" path="vendor/huawei/u8800" remote="github" revision="cm-10.1" />
  <project name="Blefish/android_kernel_huawei_u8800/" path="kernel/huawei/u8800" remote="github" revision="U8800_M7630AABBQMLZA40901040" />
  <!--remove-project name="CyanogenMod/android_hardware_qcom_display"/-->
  <project name="Blefish/android_hardware_qcom_display-msm7x30" path="hardware/qcom/display-msm7x30" remote="github" revision="cm-10.1" />
</manifest>

And this is the modification done in order to made compilable

project device/huawei/u8800/
diff --git a/BoardConfig.mk b/BoardConfig.mk
index 758a74e..bc866f6 100644
--- a/BoardConfig.mk
+++ b/BoardConfig.mk
@@ -137,7 +137,7 @@ BOARD_FLASH_BLOCK_SIZE := 262144 # (BOARD_KERNEL_PAGESIZE * 64)
 BOARD_CUSTOM_GRAPHICS := ../../../device/huawei/u8800/recovery/graphics.c
 BOARD_USE_CUSTOM_RECOVERY_FONT := \"roboto_10x18.h\"
 BOARD_HAS_NO_SELECT_BUTTON := true
-BOARD_TOUCH_RECOVERY := true
+#BOARD_TOUCH_RECOVERY := false
 
 # Custom releasetools for old partition table.
 TARGET_PROVIDES_RELEASETOOLS := true
diff --git a/libcamera/Android.mk b/libcamera/Android.mk
index a602447..642a363 100644
--- a/libcamera/Android.mk
+++ b/libcamera/Android.mk
@@ -31,7 +31,7 @@ LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc \
                     hardware/qcom/display/libgenlock \
                     hardware/qcom/media/libstagefrighthw
 
-LOCAL_SHARED_LIBRARIES:= libutils libui libcamera_client liblog libcutils libmmjpeg
+LOCAL_SHARED_LIBRARIES:= libutils libui libcamera_client liblog libcutils
 
 LOCAL_SHARED_LIBRARIES+= libgenlock libbinder
 LOCAL_SHARED_LIBRARIES+= libdl

diff --git a/proprietary-files.txt b/proprietary-files.txt
index dbabfed..369dc93 100644
--- a/proprietary-files.txt
+++ b/proprietary-files.txt
@@ -2,6 +2,7 @@ bin/qmuxd
 bin/cnd
 bin/rmt_storage
 bin/oem_rpc_svc
+lib/libmmjpeg.so
 lib/libxml.so
 lib/libcneutils.so
 lib/libcneqmiutils.so

before compile

$ cd vendor/cm
$ ./get-prebuilts
$ cd device/huawei/u8800
$ ./extract-files.sh

TROUBLESHOOTING

First of all, this is the android-building group

/bin/bash: prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi-gcc: cannot execute binary file

go to the prebuilt directory and checkout the revision with the toolchain for x86

$ cd prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/
"(android-4.1.1_r6.1)" branch :) $ git tag
android-4.1.1_r1
android-4.1.1_r1.1
android-4.1.1_r2
android-4.1.1_r3
android-4.1.1_r4
android-4.1.1_r5
android-4.1.1_r6
android-4.1.1_r6.1
android-4.1.2_r1
android-cts-4.1_r1
android-sdk-adt_r20
"(android-4.1.1_r6.1)" branch :) $ git checkout android-sdk-adt_r20

or a shortcuts

$ (cd prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/ && git checkout android-sdk-adt_r20)

INTERNALS

Understanding the Cyanogenmod is not so easy: these are the simple stuffs that I put together

vendorsetup.sh

add_launch_combo  <whatever>_<device>-eng

This is fondamental in order to compile: cm.mk, this recall the full_u8800pro.mk but you can call as you want (before ics you MUST call in this way)

## Specify phone tech before including full_phone
$(call inherit-product, vendor/cm/config/gsm.mk)

# Release name
PRODUCT_RELEASE_NAME := U8800

# Boot animation
TARGET_BOOTANIMATION_NAME := vertical-480x800

# Inherit device configuration
$(call inherit-product, device/huawei/u8800/full_u8800.mk)

# Inherit some common CM stuff.
$(call inherit-product, vendor/cm/config/common_full_phone.mk)

## Device identifier. This must come after all inclusions
PRODUCT_DEVICE := u8800
PRODUCT_NAME := cm_u8800
PRODUCT_BRAND := Huawei
PRODUCT_MODEL := U8800
PRODUCT_MANUFACTURER := Huawei

#Set build fingerprint / ID / Product Name ect.
PRODUCT_BUILD_PROP_OVERRIDES += \
	PRODUCT_NAME=u8800 \
	BUILD_DISPLAY_ID="IMM76I" \
	BUILD_FINGERPRINT=huawei/u8800:4.0.4/IMM76I/223133:userdebug/test-keys \
	PRIVATE_BUILD_DESC="huawei-user 4.0.4 IMM76I 223133 test-keys" \
	BUILD_NUMBER=223133
import android.graphics.BitmapFactory;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.content.res.Resources;
import android.graphics.Paint;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.RectF;
/**
* The aim of this class is to augment the original factory
* of Bitmap in order to allow overlaying the created Bitmap
* with indicator.
*
* {@link http://ruibm.com/?p=184}
*/
public class ExtendedBitmapFactory extends BitmapFactory {
static Bitmap decodeResourceOverlaying(Resources resources, int id, Bitmap overlay) {
final int topX = 0;
final int topY = 0;
Bitmap bg = decodeResource(resources, id);
Bitmap copyBg = Bitmap.createBitmap(bg.getWidth(), bg.getHeight(), Config.ARGB_8888);
Canvas cBg = new Canvas(copyBg);
Paint p = new Paint();
cBg.drawBitmap(bg, 0, 0, p);
Canvas c = new Canvas(copyBg);
Rect r = new Rect(topX, topY, overlay.getWidth() + topX, overlay.getHeight() + topY);
c.drawBitmap(overlay, null, r, p);
return copyBg;
}
/**
* Creates a Bitmap having a number overlayed.
*/
static Bitmap decodeResourceOverlayingWithNumber(Resources resources, int id, int number) {
final int width = 15;
final int height = 15;
final float roundPx = 7;
final int bgColor = 0xffff0000;
final int fgColor = 0xff000000;
String text = "" + number;
Bitmap numberBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
Canvas c = new Canvas(numberBitmap);
Paint p = new Paint();
Rect r = new Rect(0, 0, width, height);
final RectF rectF = new RectF(r);
p.setColor(bgColor);
c.drawRoundRect(rectF, roundPx, roundPx, p);
p.setColor(fgColor);
Rect bounds = new Rect();
p.getTextBounds(text, 0, text.length(), bounds);
c.drawText(
text,
0, text.length(),
- (bounds.right/2) + (width/2), - (bounds.top/2) + (height/2),
p);
return decodeResourceOverlaying(resources, id, numberBitmap);
}
}
import android.database.Cursor;
import android.os.Bundle;
import java.util.Observable;
/**
* Interface to be implemented by a model to be called with SimpleCursorLoader.
*
* The "args" contains the parameter with respect to filter the query.
*/
public interface IModelFilter {
public Cursor get(Bundle args);
public Observable getObservable();
}
import android.view.ViewGroup;
import com.nineoldandroids.animation.IntEvaluator;
import com.nineoldandroids.animation.TypeEvaluator;
/**
* This evaluator is used in animation of "layouting" a view.
*
* Remember: the LayoutParams MUST be the parent one!
*
* Created by Gianluca Pacchiella <pacchiella@elipse.it> on 9/4/13.
*/
public class LayoutParamsEvaluator<T extends ViewGroup.LayoutParams> implements TypeEvaluator<T> {
private T mLayoutParams = null;
static private IntEvaluator intEvaluator = new IntEvaluator();
@Override
public T evaluate(float t, T startLayoutParams, T finalLayoutParams) {
if (mLayoutParams == null) {
//mLayoutParams = new ViewGroup.LayoutParams(startLayoutParams);
mLayoutParams = startLayoutParams;
}
mLayoutParams.width = intEvaluator.evaluate(t, startLayoutParams.width, finalLayoutParams.width);
mLayoutParams.height = intEvaluator.evaluate(t, startLayoutParams.height, finalLayoutParams.height);
return mLayoutParams;
}
}

List of interesting libraries

import android.graphics.Matrix;
import android.util.Log;
import com.nineoldandroids.animation.FloatEvaluator;
import com.nineoldandroids.animation.TypeEvaluator;
/**
* Created by Gianluca Pacchiella <pacchiella@elipse.it> on 8/29/13.
*/
public class MatrixEvaluator implements TypeEvaluator<Matrix> {
static String TAG = "MatrixEvaluator";
static float[] valuesStart = new float[9];
static float[] valuesEnd = new float[9];
static float[] valuesCalculation = new float[9];
static private Matrix finalMatrix = new Matrix();
static private FloatEvaluator floatEvaluator = new FloatEvaluator();
@Override
public Matrix evaluate(float t, Matrix startMatrix, Matrix endMatrix) {
// retrieve the values of the matrix
startMatrix.getValues(valuesStart);
endMatrix.getValues(valuesEnd);
/**
* Now we calculate the difference value between the matrix entries but not for rotation
* because is not so simple and for now we want only to translate/scale all the things.
*/
finalMatrix.reset();// so we have an identity matrix to work with
finalMatrix.getValues(valuesCalculation);
valuesCalculation[Matrix.MTRANS_X] = floatEvaluator.evaluate(t, valuesStart[Matrix.MTRANS_X], valuesEnd[Matrix.MTRANS_X]);
valuesCalculation[Matrix.MTRANS_Y] = floatEvaluator.evaluate(t, valuesStart[Matrix.MTRANS_Y], valuesEnd[Matrix.MTRANS_Y]);
valuesCalculation[Matrix.MSCALE_X] = floatEvaluator.evaluate(t, valuesStart[Matrix.MSCALE_X], valuesEnd[Matrix.MSCALE_X]);
valuesCalculation[Matrix.MSCALE_Y] = floatEvaluator.evaluate(t, valuesStart[Matrix.MSCALE_Y], valuesEnd[Matrix.MSCALE_Y]);
finalMatrix.setValues(valuesCalculation);
return finalMatrix;
}
}
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.content.AsyncTaskLoader;
import java.util.Observable;
import java.util.Observer;
public class SimpleCursorLoader extends AsyncTaskLoader<Cursor> implements Observer {
private Context mContext;
private Integer mId = null;
private IModelFilter mModel = null;
private Bundle mArgs;
private final static String TAG = "LOADER";
public SimpleCursorLoader(Context context, Integer _id) {
super(context);
mContext = context;
mId = _id;
}
public SimpleCursorLoader(Context context, IModelFilter model, Bundle args) {
super(context);
mContext = context;
mModel = model;
mArgs = args;
model.getObservable().addObserver(this);
}
@Override
protected void onStartLoading() {
android.util.Log.d(TAG, "onStartLoading()");
super.onStartLoading();
// TODO: more logic here (see http://developer.android.com/reference/android/content/AsyncTaskLoader.html)
forceLoad();
}
@Override
public Cursor loadInBackground() {
android.util.Log.d(TAG, "loadInBackground()");
return mModel.get(mArgs);
}
@Override
public void update(Observable obs, Object data) {
android.util.Log.d(TAG, "update()");
onContentChanged();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment