顯示具有 Android 標籤的文章。 顯示所有文章
顯示具有 Android 標籤的文章。 顯示所有文章

2018年9月18日 星期二

Use reflection to get framework hide variable value or resource value

Code snippet:

1. Get hide constant value
public static int getHideIntConstants(String classAndPkgName, String fieldName, int defaultValue){
    int fieldValue = defaultValue;

    Class<?> c = null;
    try {
        c = Class.forName(classAndPkgName);
        Field field = c.getDeclaredField(fieldName);
        field.setAccessible(true);
        fieldValue = field.getInt(null);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (Exception e){
        e.printStackTrace();
    }
    String hesString = Integer.toHexString(fieldValue);
    Log.d(TAG, "fieldValue " + fieldName + ": " + fieldValue + " ; hex: " + hesString);
    return fieldValue;
}

2. Get hide constant value declared in inner class
public static int getTypeDisplayOverlayInt(Window window) {
    int typeDisplayOverlay = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

    Class<?> c = null;
    try {
        c = Class.forName("android.view.WindowManager");
        Class<?>[] classes = c.getDeclaredClasses();
        for(Class innerClass: classes){
            if(innerClass.getName().contains("LayoutParams")){
                Field field = innerClass.getDeclaredField("TYPE_DISPLAY_OVERLAY");
                field.setAccessible(true);
                typeDisplayOverlay = field.getInt(window.getAttributes());
                break;
            }
        }
    } catch (Exception e){
        e.printStackTrace();
    }
    return typeDisplayOverlay;
}

3. Get resource value
public static int getStatusHeight(Context context) {
    int statusBarHeight = -1;
    try {
        Class<?> clazz = Class.forName("com.android.internal.R$dimen");
        Object object = clazz.newInstance();
        int height = Integer.parseInt(clazz.getField("status_bar_height").get(object).toString());
        statusBarHeight = context.getResources().getDimensionPixelSize(height);
    } catch (Exception e) {
        e.printStackTrace();
    }

    return statusBarHeight;
}

4. Get SystemUI apk recource value
public static String getDateFormat(Context context) {
    PackageManager pm = context.getPackageManager();
    try {
        Resources resources = pm.getResourcesForApplication("com.android.systemui");
        int id = resources.getIdentifier("abbrev_wday_month_day_no_year", "string", "com.android.systemui");
        if (id > 0) {
            return resources.getString(id);
        } else {
            return null;
        }

    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }
    return null;
}

2018年5月17日 星期四

How to fix INSTALL_FAILED_TEST_ONLY error

Reference:

https://www.jianshu.com/p/8f5730cab8fc
http://www.cnblogs.com/yongfengnice/p/7814016.html
https://blog.csdn.net/chf1142152101/article/details/70738868

Solution:

1. Add the following line into gradle.properties

    ......
    android.injected.testOnly=false


2. Click Android Studio "Build -> BuildAPK(s)" to generate apk

3. Sign key
4. If gradle version is test version, revise it to release version

buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.4.0-alpha3' //版本为测试版 } }

2018年4月6日 星期五

Get height of status bar

Reference:

https://gist.github.com/hamakn/8939eb68a920a6d7a498

Code snippet:

public static int getStatusHeight(Context context) {
    int statusBarHeight = -1;
    try {
        Class<?> clazz = Class.forName("com.android.internal.R$dimen");
        Object object = clazz.newInstance();
        int height = Integer.parseInt(clazz.getField("status_bar_height").get(object).toString());
        statusBarHeight = context.getResources().getDimensionPixelSize(height);
    } catch (Exception e) {
        e.printStackTrace();
    }

    return statusBarHeight;
}

Detect device orientation by OrientationEventListener

Reference:
http://blog.csdn.net/zxccxzzxz/article/details/52282256

Code snippet:
private int mLastRotation = -1;
mOrientationEventListener = new OrientationEventListener(this,
        SensorManager.SENSOR_DELAY_NORMAL) {
    @Override    public void onOrientationChanged(int orientation) {
        if (orientation == ORIENTATION_UNKNOWN) {
            return;
        }
        Display display = windowManager.getDefaultDisplay();
        int rotation = display.getRotation();
        if (mLastRotation == DEFAULT_ROTATION){
            mLastRotation = rotation;
        } else if (rotation != mLastRotation) {
            mLastRotation = rotation;
            // notify orientation change
        }
    }
};

2018年4月5日 星期四

Change the menu style on ActionBar

Reference:

http://www.itstrike.cn/Question/c9ee24fa-9e1a-4154-a304-1fd41d418561.html

Code snippet:

1. Background

AndroidManifest.xml
<application    ......
    android:theme="@style/AppTheme">

style.xml
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">   
    <!-- Customize actionbar overflow menu-->    <item name="actionOverflowMenuStyle">@style/My.Widget.Material.Light.PopupMenu.Overflow</item>    
</style>

<style name="My.Widget.Material.Light.PopupMenu.Overflow" parent="android:Widget.Material.Light.PopupMenu.Overflow">
    <item name="android:popupBackground">@drawable/my_popup_background_material</item>
</style>


drawable/my_popup_background_material.xml
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"       android:shape="rectangle">
    <corners            android:radius="12dp" />
    <solid            android:color="@color/action_bar_color" />
</shape>

2. List choice background
activity_layout.xml
......
<android.support.v7.widget.Toolbar    android:id="@+id/tool_bar"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:background="@color/action_bar_color"    android:theme="@style/AppTheme.AppBarOverlay"    app:contentInsetStartWithNavigation="0dp"    app:popupTheme="@style/AppTheme.PopupOverlay" >

style.xml
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light">
    <item name="android:textColor">@color/list_item_title</item>
    <item name="android:textSize">18sp</item>
    <item name="android:textStyle">normal</item>
    <item name="android:listChoiceBackgroundIndicator">@drawable/my_list_choice_background_material</item>
</style>

drawable/my_list_choice_background_material.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"        android:color="@color/list_highlight_material">
    <item>
        <shape android:shape="rectangle">
            <corners android:radius="12dp"/>
            <solid android:color="@color/action_bar_color" />
        </shape>
    </item>
</ripple>

How to import org.apache.http library to Android Studio

Reference:

https://dotblogs.com.tw/newmonkey48/2016/02/22/140802

Code snippet:

build.gradle

android {
    useLibrary 'org.apache.http.legacy'
}

Add a customized theme to AlertDialog

Reference:

http://blog.supenta.com/2014/07/02/how-to-style-alertdialogs-like-a-pro/

Code snippet:

Context mThemeContext = new ContextThemeWrapper(this, R.style.customized_theme);
View dialogView = View.inflate(mThemeContext, R.layout.my_dialog, null);
AlertDialog.Builder aBuilder = new AlertDialog.Builder(mThemeContext);
aBuilder.setView(dialogView);

// setup your AlertDialog
......

AlertDialog aDialog = aBuilder.create();
aDialog.show();

2018年3月28日 星期三

Disabling screen shot capture in Android application

Reference:





只要在呼叫setContentView()之前設定FLAG_SECUREwindows flag,這個頁面就無法被截圖或錄影
按  hardware key截圖時,會出現下列的log

01-01 21:11:50.538 10930-10930/? D/ScreenshotUtils: notifyScreenShotError, first screenshot

Code snippet:

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

    getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
            WindowManager.LayoutParams.FLAG_SECURE);

    setContentView(R.layout.activity_main);
    ...
}

2018年2月5日 星期一

Add/Remove Toolbar elevation

Reference:

http://blog.iamsuleiman.com/add-a-toolbar-elevation-on-pre-lollipop/
https://www.reddit.com/r/androiddev/comments/2k50fw/elevation_on_toolbar_not_working_on_prelollipop/
https://www.jianshu.com/p/802545cec682

Code snippet:

Add elevation
toolbar.setElevation(elevation);

Remove elevation
toolbar.setElevation(0);

Difference between removing an app from recent app list and click “Force Stop” button in Settings app info page

Reference:

https://android.stackexchange.com/questions/132929/difference-between-killing-an-app-by-clearing-it-from-recent-apps-menu-and-forc

Description:

從 Recent app list將app移除,並不會kill掉app process,只會將activity關閉,背景在執行service並不會停止運作。要將整個process kill掉,要從Settings app info頁面,將app force stop。



Change the color of toolbar overflow icon

Reference:

Method 1:
https://snow.dog/blog/how-to-dynamicaly-change-android-toolbar-icons-color/
https://stackoverflow.com/questions/43537958/change-toolbar-overflow-icon-color/43539097
https://futurestud.io/tutorials/android-quick-tips-8-how-to-dynamically-tint-actionbar-menu-icons

Method 2:
https://www.murrayc.com/permalink/2014/10/28/android-changing-the-toolbars-text-color-and-overflow-icon-color/
https://stackoverflow.com/questions/27995461/appcompat-toolbar-change-overflow-icon-color-in-actionmode


Code snippet:

Method 1:
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
    <item name="android:textColorPrimary">@color/action_bar_text_color</item>
    <!-- change the overflow icon color (three vertical dots) -->    <item name="android:tint">@color/action_bar_overflow_icon_color</item>
    <item name="android:textSize">20sp</item>
    <item name="android:textStyle">bold</item>
    <item name="android:fontFamily">Roboto Medium</item>
</style>

2018年2月4日 星期日

Change the color of status bar and icon/text

Reference:

https://developer.android.com/training/material/theme.html
https://solinariwu.blogspot.tw/2017/05/android-status-bar.html

Code snippet:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize the status bar color -->    <item name="android:statusBarColor">@color/status_bar_color</item>
    <!-- If set, the status bar will be drawn such that it is compatible with a light status bar background -->    <item name="android:windowLightStatusBar">true</item>
</style>

2018年2月1日 星期四

Change navigation bar color

Reference:

https://stackoverflow.com/questions/27839105/android-lollipop-change-navigation-bar-color

Code snippet:

styles.xml
<item name="android:navigationBarColor">@color/theme_color</item>

XXX.java
window.setNavigationBarColor(@ColorInt int color)

Check if device is locked

Reference:

https://stackoverflow.com/questions/8317331/detecting-when-screen-is-locked

Code snippet:

KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
boolean isPhoneLocked = keyguardManager.inKeyguardRestrictedInputMode();

Completely transparent status bar and navigation bar

Reference:

https://stackoverflow.com/questions/29069070/completely-transparent-status-bar-and-navigation-bar-on-lollipop


Code snippet:


getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
        WindowManager.LayoutParams.
FLAG_LAYOUT_NO_LIMITS);



<style name="FullScreenTheme" parent="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>

2017年12月25日 星期一

Get the user id (Check if the user is owner)

Reference:
https://stackoverflow.com/questions/14749504/android-usermanager-check-if-user-is-owner-admin
http://blog.csdn.net/zhanglianyu00/article/details/50238447
http://blog.csdn.net/zhanglianyu00/article/details/50253187
http://gityuan.com/2016/11/20/user_manager/


Code snippet:
public static long getUserId(Context context){
    UserHandle uh = Process.myUserHandle();
    UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
    long userSerialNumber = -1;
    if(null != um) {
        userSerialNumber = um.getSerialNumberForUser(uh);
    }
    return userSerialNumber;
}

Get duration of the video by uri

Reference:

https://stackoverflow.com/questions/33770188/how-can-i-get-the-duration-resolution-of-a-video-file-programmatically-in-andro/33770238


Code snippet:

MediaPlayer mp = MediaPlayer.create(this, Uri.parse(uriOfFile));
if(mp == null){
    Log.e(TAG, "The record file is invalid");
     return;
}
int duration = mp.getDuration();

Detect switching between users

Reference:

https://stackoverflow.com/questions/15392126/how-to-detect-switching-between-users


Description:

Listen the ACTION_USER_BACKGROUND and ACTION_USER_FOREGROUND broadcast to detect switching between users.


Code snippet:


IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_BACKGROUND);
filter.addAction(Intent.ACTION_USER_FOREGROUND);
registerReceiver(mUserSwitchReceiver, filter);



public class UserSwitchReceiver extends BroadcastReceiver {
    private static final String TAG = "UserSwitchReceiver";
    @Override    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        
        if(Intent.ACTION_USER_FOREGROUND.equals(action)){
            // Todo: do something when switch in the user
        } else if(Intent.ACTION_USER_BACKGROUND.equals(action)){
            // Todo: do something when switch out the user
        }
    }
}

2017年12月5日 星期二

當Low memory時,Activity被銷毀了,但是Fragment重複產生

Reference:

http://juniperphoton.net/2017/03/27/jie-jue-viewpager-fragment-de-hui-fu-wen-ti/
http://y-anz-m.blogspot.tw/2013/07/viewpager-fragment.html
http://www.voidcn.com/article/p-weicgtjm-kv.html

Issue description:

當Low memory時,process被系統刪除,Activity被銷毀了,但是Fragment還在,導致Fragment重疊,造成開啟app的時間不斷增加

使用 adb shell dumpsys activity top 指令
可以發現 fragment數量不停累加

Solution:

在Activity被銷毀前,先將正在使用的fragment object儲存起來
下次開啟app後,再將前一次使用的fragment object (現在用不到的) 刪除掉

Code snippet:

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        // Store the current used fragments
        if (mFragmentAdapter != null) {
            getSupportFragmentManager().putFragment(outState, KEY_FRAG_NAME1, mFragmentAdapter.getFragment(0));
            getSupportFragmentManager().putFragment(outState, KEY_FRAG_NAME2, mFragmentAdapter.getFragment(1));
        }
    }

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
.................
        // Remove previous unused fragments
        if (savedInstanceState != null) {
            mFragment1 = getSupportFragmentManager().getFragment(savedInstanceState,
                    KEY_FRAG_NAME1);
            mFragment2 = getSupportFragmentManager().getFragment(savedInstanceState,
                    KEY_FRAG_NAME2);

            if(mFragment1 != null || mFragment2 != null){
                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                transaction.remove(mFragment1 );
                transaction.remove(mFragment2 );
                transaction.commit();
            }
        }
...............
    }

2017年11月22日 星期三

Notification icon flash on status bar

Problem:


當需要在短時間內持續更新notification的內容時
在建立Notification時,記得使用同一個Notification Builder物件,並且設定 setOnlyAlertOnce(true)
以免SystemUI一直在update notification,造成status bar UI一直在跳動

Code snippet:


return new Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
            mBuilder
                        .setContentTitle(title)
                        .setContentText(contentText)
                        .setContentIntent(contentIntent)
                        .setSmallIcon(R.drawable.noti_icon)
                        .setLargeIcon(appIcon)
                        .setSubText(appLabel)
                        .setColor(color)
                        .setOnlyAlertOnce(true)
                        .addAction(stopAction)
                        //.addAction(optionsAction)

                        .build();