Moon Light Box

Time is Money

Posts match “ android ” tag:

Android Studio - Github Project PagerSlidingTabStrip Build Error

| Comments

I imported Github PagerSlidingTabStrip project into Android Studio 0.8.2.

Oops. And it wasted me a lot of time to fix build error.

To avoid encountered the same problems.

I noted solutions here and hoped this can help you. :)

Build Error 1.

Error:Build script error, unsupported Gradle DSL method found: 'getBootClasspath()'!

Possible causes could be:
  - you are using Gradle version where the method is absent Fix Gradle settings
  - you didn't apply Gradle plugin which provides the method Apply Gradle plugin
  - or there is a mistake in a build script Goto source

Modified PagerSlidingTabStrip / build.gradle.

---classpath 'com.android.tools.build:gradle:0.6.+'
+++classpath 'com.android.tools.build:gradle:0.12.+'

Modified PagerSlidingTabStrip / gradle / wrapper / gradle-wrapper.properties

---distributionUrl=http\://services.gradle.org/distributions/gradle-1.8-all.zip
+++distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip

Build Error 2.

Error:Could not find property 'allJava' on source set main.

Modified PagerSlidingTabStrip / library / build.gradle

---apply from: 'https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle'

Build Error 3.

Error:The SDK Build Tools revision (19.0.0) is too low for project ':library'. Minimum required is 19.1.0

Modified PagerSlidingTabStrip / gradle.properties

---ANDROID_BUILD_TARGET_SDK_VERSION=19
---ANDROID_BUILD_TOOLS_VERSION=19
---ANDROID_BUILD_SDK_VERSION=19
+++ANDROID_BUILD_TARGET_SDK_VERSION=20
+++ANDROID_BUILD_TOOLS_VERSION=20
+++ANDROID_BUILD_SDK_VERSION=20

Reference : Github PagerSlidingTabStrip Project

3C - Samsung Galaxy Tab4 Crash

| Comments

Issue description :

- Black Screen
- All keys not responding

Solution :

- Press Power Key + Volume Down Key about 10 second
- Then phone will reboot

Android - ActionMode

| Comments

ActionMode is supported on library android.support.v7.

An action mode's lifecycle is as follows and we need override it.

  • onCreateActionMode(ActionMode, Menu) once on initial creation
  • onPrepareActionMode(ActionMode, Menu) after creation and any time the ActionMode is invalidated
  • onActionItemClicked(ActionMode, MenuItem) any time a contextual action button is clicked
  • onDestroyActionMode(ActionMode) when the action mode is closed
MainActivity.java
public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (savedInstanceState == null) {
            initMainFragment();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        return super.onOptionsItemSelected(item);
    }
    
    private void initMainFragment() {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new MainFragment()).commit();
    }
}
MainFragment.java
public class MainFragment extends Fragment {
    private Activity mActivity;
    private ActionModeCallBack mActionModeCallBack;

    @Override
    public View onCreateView(
            LayoutInflater inflater,
            ViewGroup container,
            Bundle savedInstanceState) {
        View rootView =
                inflater.inflate(R.layout.fragment_main, container, false);
        return rootView;
    }
    
    @Override  
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        mActivity = activity;
    }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        mActivity.finish();
        mActionModeCallBack.stop();
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.main, menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            startActionMode();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
    
    private void startActionMode() {
        mActionModeCallBack = new ActionModeCallBack(mActivity);
        mActionModeCallBack.start();
    }
}
ActionModeCallBack.java
public class ActionModeCallBack implements ActionMode.Callback {
    private Activity mActivity;
    
    public ActionModeCallBack(Activity activity) {
        mActivity = activity;
    }

    public void start() {
        mActivity.startActionMode(this);
    }
    
    public void stop() {
        mActivity.finish();
    }
    
    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        return false;
    }

    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        mode.getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public void onDestroyActionMode(ActionMode mode) {
        mode = null;
    }

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        return false;
    }
}

Android - Service

| Comments

  1. Service is a non-UI application.
  2. Service is running in Main Thread.
  3. Service has two forms : Started and Bound.

We need override four methods.

  • onStartCommand()
  • onBind()
  • onCreate()
  • onDestroy()

Here is a Started example.
Activity is simple calling Service to work in background.
There is no interaction between Activity and Service.

MainActivity.java
public class MainActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (savedInstanceState == null) {
            initMainFragment();
        }
    }

    private void initMainFragment() {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new MainFragment()).commit();
    }
}
MainFragment.java
public class MainFragment extends Fragment implements OnClickListener {
    private Activity mActivity;
  
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        mActivity = activity;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);
        ((Button) rootView.findViewById(R.id.start_service)).setOnClickListener(this);
        ((Button) rootView.findViewById(R.id.stop_service)).setOnClickListener(this);
        return rootView;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.start_service:
            mActivity.startService(new Intent(mActivity, MainService.class));
            break;
        case R.id.stop_service:
            mActivity.stopService(new Intent(mActivity, MainService.class));
            break;
        default:
            break;
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mActivity.finish();
    }
}
MainService.java
public class MainService extends Service {
    public static final String TAG = "MainService";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate() executed");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand() executed");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy() executed");
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.service"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!-- ↓↓↓↓↓↓ Register Your Service Here ↓↓↓↓↓↓ -->
        <service android:name="com.example.service.MainService" />
        <!-- ↑↑↑↑↑↑ Register Your Service Here ↑↑↑↑↑↑ -->
    </application>

</manifest>

You can see the logcat message when click buttons.

D/MainService(8297): onCreate() executed
D/MainService(8297): onStartCommand() executed
D/MainService(8297): onDestroy() executed

Reference:http://developer.android.com/guide/components/services.html
Reference:http://blog.csdn.net/guolin_blog/article/details/11952435

Android - Install Android Developer Tools on Mac OS 10.10 Yosemite

| Comments

Problem

If you occurred below error message when you open a new Android Project, please upgrade JDK7 to JDK8.
Because Mac OS 10.10 Yosemite doesn't support JDK7 or lower.

Errors running builder 'Android Resource Manager' on Project java.lang.NullPointerException

Step1.

Download Android Developer Tools as follows.

  1. Eclipse Java Luna
  2. Android SDK 23.0.2
  3. JDK 8 Update 25

Step2.

Remove old version JDK.

  1. Finder -> Search JavaAppletPlugin.plugin -> Move JavaAppletPlugin.plugin to Trash
  2. Remove /Library/Java/JavaVirtualMachines/jdk<major>.<minor>.<macro[update]>.jdk

Step3.

Double-click jdk-8u25-macosx-x64.dmg then install it and you can check result in terminal.

Step3.

Start Eclipse -> Help -> Install New Software -> Add -> Enter Name and Location

  1. Name: ADT Plugin
  2. Location: https://dl-ssl.google.com/android/eclipse/

Android - Clean Code 1

| Comments

We always write this statement. And it is difficult to read.

TextView textView = (TextView) findViewById(R.id.exampleTextView);
ImageView imageView = (ImageView) findViewById(R.id.exampleImageView);
Button button = (Button) findViewById(R.id.exampleButton);

Due to those components inherit android.view.View, we can use this method to clean code.

public final <E extends View> E getView(int id) {
    return (E) findViewById(id);
}
@SuppressWarnings("unchecked")
protected <E extends View> E getView(int viewId) {
    View view = sparseArray.get(viewId);
    if (view == null) {
        view = contentView.findViewById(viewId);
        sparseArray.put(viewId, view);
    }
    return (E) view;
}

Then your code will become this. So clear! HaHa.

TextView textView = getView(R.id.exampleTextView);
ImageView imageView = getView(R.id.exampleImageView);
Button button = getView(R.id.exampleButton);

Reference:http://ysl-paradise.blogspot.tw/2014/04/activitygetview.html

Android - KitKat Support Java 7

| Comments

ADT 22.6.0 (March 2014)

General Notes:
Added support for Java 7 language features like multi-catch, try-with-resources, and the diamond operator. These features require version 19 or higher of the Build Tools. Try-with-resources requires minSdkVersion 19; the rest of the new language features require minSdkVersion 8 or higher. To use the new language features after installing ADT 22.6.0, ensure that you run Eclipse on JDK 7 and change your application project settings to use JDK 7.

Reference:http://developer.android.com/tools/sdk/eclipse-adt.html

Android - /storage/emulated/legacy vs /storage/emulated/0

| Comments

Usually, we get the external storage via this

Environment.getExternalStorageDirectory().getAbsolutePath();

And get the result.

/storage/emulated/0

Then we use adb to see the path.

adb shell ls -la /storage/emulated/0
/storage/emulated/0: No such file or directory

Again, we can see the correct path.

adb shell ls -la /storage/emulated/
lrwxrwxrwx root     root              2015-04-22 14:05 legacy -> /mnt/shell/emulated/0

But how do we get /storage/emulated/legacy?
According to AOSP, we can echo $EXTERNAL_STORAGE.

adb shell echo $EXTERNAL_STORAGE
/storage/emulated/legacy

Use code method.

System.getenv("EXTERNAL_STORAGE");

Reference:http://developer.android.com/guide/topics/data/data-storage.html#filesExternal

Android - FileObserver Cannot Work in KitKat and Lollipop

| Comments

From Android Developers, we can use FileObserver to know files or folders changed on sdcard.

We usually use this to implement.

public class StorageMonitor extends FileObserver {
    public StorageMonitor(String path) {
        super(path);
    }

    @Override
    public void onEvent(int event, String path) {
        switch (event) {
            case FileObserver.ACCESS:
                Log.i("FileObserver", "ACCESS: " + path);
                break;
            case FileObserver.ATTRIB:
                Log.i("FileObserver", "ATTRIB: " + path);
                break;
            case FileObserver.CLOSE_NOWRITE:
                Log.i("FileObserver", "CLOSE_NOWRITE: " + path);
                break;
            case FileObserver.CLOSE_WRITE:
                Log.i("FileObserver", "CLOSE_WRITE: " + path);
                break;
            case FileObserver.CREATE:
                Log.i("FileObserver", "CREATE: " + path);
                break;
            case FileObserver.DELETE:
                Log.i("FileObserver", "DELETE: " + path);
                break;
            case FileObserver.DELETE_SELF:
                Log.i("FileObserver", "DELETE_SELF: " + path);
                break;
            case FileObserver.MODIFY:
                Log.i("FileObserver", "MODIFY: " + path);
                break;
            case FileObserver.MOVE_SELF:
                Log.i("FileObserver", "MOVE_SELF: " + path);
                break;
            case FileObserver.MOVED_FROM:
                Log.i("FileObserver", "MOVED_FROM: " + path);
                break;
            case FileObserver.MOVED_TO:
                Log.i("FileObserver", "MOVED_TO: " + path);
                break;
            case FileObserver.OPEN:
                Log.i("FileObserver", "OPEN: " + path);
                break;
            default:
                Log.i("FileObserver", "DEFAULT(" + event + "): " + path);
                break;
        }
    }
}

And start StorageMonitor in onCreat().

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    String sdcard = Environment.getExternalStorageDirectory().getAbsolutePath();
    StorageMonitor storageMonitor = new StorageMonitor(sdcard);
    storageMonitor.startWatching();
}

Launched application and modified files/folders on sdcard. Then I cannot see any event printed in logcat. I tried several Android Phones and versions (HTC ONE X 4.2.2, Samsung Note3 4.4.2, Google Nexus5 5.0...etc). FileObserver worked well in some Android Phones, for example, HTC ONE X 4.2.2 always passed.

Last, I try to use other constructor of FileObserver. It works for all!!

public StorageMonitor(String path) {
    super(path, FileObserver.ALL_EVENTS);
}

God, is this Google bug?

Android - Warning:Conflict with dependency 'com.android.support:support-annotations'.

| Comments

We use gradle to import libraries. And it will cause dependency problem.

Gradle build error message:

Warning:Conflict with dependency 'com.android.support:support-annotations'. Resolved versions for app (20.0.0) and test app (22.0.0) differ.

Solution:

Add below configure in build.gradle file.

allprojects {
    ...
    configurations.all {
        resolutionStrategy.force 'com.android.support:support-annotations:23.0.0'
    }
    ...
}

Reference:http://code.google.com/p/android-test-kit/issues/detail?id=136
Reference:https://github.com/googlesamples/android-testing/issues/22

Android - finished with non-zero exit value 3

| Comments

Gradle build error message:

When your Android project contains too many class, Android Studio will throw non-zero exit value 3 during dex apk period.

Error:org.gradle.process.internal.ExecException: Process 'command 'C:\Program Files\Java\jdk1.7.0_67\bin\java.exe'' finished with non-zero exit value 3

Solution:

Add below configure in build.gradle file.

dexOptions {
    javaMaxHeapSize "4g"
}

Reference:http://stackoverflow.com/questions/31605291

Android - Volley Build Failed in Android SDK 23

| Comments

Apache HTTP Client Removal start from Android SDK 23. So we have to add they back manually.

The org.apache.http.legacy.jar is in Android/sdk/platforms/android-23/optional and copy it to your Android project. For exmple, libs folder.

1. Modified build.gradle file with below changes.

dependency {
    compile project('libs/org.apache.http.legacy.jar')
}

or

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

2. Modified proguard files.

Warning:library class org.apache.http.conn.scheme.LayeredSocketFactory extends or implements program class org.apache.http.conn.scheme.SocketFactory
Warning:library class android.webkit.WebView depends on program class android.net.http.SslCertificate
Warning:library class android.webkit.WebViewClient depends on program class android.net.http.SslError
Warning:library class org.apache.http.params.HttpConnectionParams depends on program class org.apache.http.params.HttpParams
-keep class org.apache.http.** { *; }
-dontwarn org.apache.http.**
-dontwarn android.net.**

Reference:https://github.com/mcxiaoke/android-volley/issues/92
Reference:http://developer.android.com/preview/behavior-changes.html#behavior-apache-http-client

Linux - Install Android SDK in CentOS7 (Updated 2017-07-24)

| Comments

Updated 2017-07-24. Android SDK API/BuildTool 26 Released.

Step 1. Download and Install Android SDK.

# mkdir -p /opt/sdk-tools-linux-3859397
# cd /opt/sdk-tools-linux-3859397
# sudo wget https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
# sudo unzip sdk-tools-linux-3859397.zip
# cd /opt
# sudo chown -R root:root sdk-tools-linux-3859397
# sudo ln -s sdk-tools-linux-3859397 android-sdk

Step 2. Set Android SDK Environment Value.

# sudo vim /etc/profile.d/android-sdk-env.sh

export ANDROID_HOME="/opt/android-sdk"
export PATH="$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$PATH"

# sudo source /etc/profile.d/android-sdk-env.sh

Step 3.1 Update Android SDK.

# cd /opt/android-sdk/tools
# sudo ./android update sdk --no-ui

Step 3.2 Update Android SDK.

Use Command Line to Update Android SDK

This is an example.
# /opt/android-sdk/tools/bin/sdkmanager --list
# /opt/android-sdk/tools/bin/sdkmanager "tools" "build-tools;26.0.0" "extras;android;m2repository" "extras;google;google_play_services" "platforms;android-26" "platform-tools"

Android - permission vs uses-permission

| Comments

In App A, you will be a sender. And it need declare your custom permission.

<permission android:name="AAA.BBB.CCC" 
            android:label="APP_A" 
            android:protectionLevel="signature" />

In App B, you will be a receiver.

<uses-permission android:name="AAA.BBB.CCC"/>
.
.
.
<receiver 
        android:name="my.app.BroadcastReceiver"
        android:permission="AAA.BBB.CCC">
        <intent-filter>
            <action android:name="my.app.Action" />
        </intent-filter>
</receiver>

https://stackoverflow.com/questions/8816623/how-to-use-custom-permissions-in-android/8817231#8817231

https://stackoverflow.com/questions/11770794/how-to-set-permissions-in-broadcast-sender-and-receiver-in-android

https://stackoverflow.com/questions/14450839/uses-permission-vs-permission-for-android-permissions-in-the-manifest-xml-file