Showing posts with label android-5.0-lollipop. Show all posts
Showing posts with label android-5.0-lollipop. Show all posts

Saturday, May 6, 2017

Android 5.x ClassNotFoundException works fine on 6.0+

Leave a Comment

I have updated my project's minSdkVersion from 19 to 21. This has caused an issue on 5.0/5.1 devices where I can't run the app. I keep getting a ClassNotFoundException on my Application class. The full log, Application class, and gradle file are below. If I revert my project back to minSdkVersion 19 then the app will run on 4.4+ with no problems.

What I have tried

  • Cleaning/Rebuilding

  • Updating and downgrading the build tools version

  • All support library's across projects have same version number

  • Making all my manifest classes relative and then absolute

  • Updated all Sdk and build tools

Log

04-27 14:37:07.152 6278-6278/? E/AndroidRuntime: FATAL EXCEPTION: main      Process: com.package.testapp, PID: 6278      java.lang.RuntimeException: Unable to instantiate application com.package.TestApplication: java.lang.ClassNotFoundException: Didn't find class "com.package.Application" on path: DexPathList[[zip file "/data/app/com.package.testapp-1/base.apk"],nativeLibraryDirectories=[/data/app/com.package.testapp-1/lib/x86_64, /vendor/lib64, /system/lib64]]          at android.app.LoadedApk.makeApplication(LoadedApk.java:563)          at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4526)          at android.app.ActivityThread.access$1500(ActivityThread.java:151)          at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1364)          at android.os.Handler.dispatchMessage(Handler.java:102)          at android.os.Looper.loop(Looper.java:135)          at android.app.ActivityThread.main(ActivityThread.java:5254)          at java.lang.reflect.Method.invoke(Native Method)          at java.lang.reflect.Method.invoke(Method.java:372)          at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)       Caused by: java.lang.ClassNotFoundException: Didn't find class "com.package.TestApplication" on path: DexPathList[[zip file "/data/app/com.package.testapp-1/base.apk"],nativeLibraryDirectories=[/data/app/com.package.testapp-1/lib/x86_64, /vendor/lib64, /system/lib64]]          at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)          at java.lang.ClassLoader.loadClass(ClassLoader.java:511)          at java.lang.ClassLoader.loadClass(ClassLoader.java:469)          at android.app.Instrumentation.newApplication(Instrumentation.java:980)          at android.app.LoadedApk.makeApplication(LoadedApk.java:558)          at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4526)           at android.app.ActivityThread.access$1500(ActivityThread.java:151)           at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1364)           at android.os.Handler.dispatchMessage(Handler.java:102)           at android.os.Looper.loop(Looper.java:135)           at android.app.ActivityThread.main(ActivityThread.java:5254)           at java.lang.reflect.Method.invoke(Native Method)           at java.lang.reflect.Method.invoke(Method.java:372)           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)          Suppressed: java.lang.ClassNotFoundException: com.package.testapp.welcome.TestClaimApplication          at java.lang.Class.classForName(Native Method)          at java.lang.BootClassLoader.findClass(ClassLoader.java:781)          at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)          at java.lang.ClassLoader.loadClass(ClassLoader.java:504)                 ... 13 more       Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available 

Gradle

    buildscript {     repositories {         maven { url 'https://maven.fabric.io/public' }     }      dependencies {         classpath 'io.fabric.tools:gradle:1.+'     }     }      apply plugin: 'com.android.application'     apply plugin: 'io.fabric'      repositories {     maven { url 'https://maven.fabric.io/public' }     }  android {      compileSdkVersion 25     buildToolsVersion '25.0.3'      defaultConfig {         applicationId "com.package.testapp"         minSdkVersion 21         multiDexEnabled = true         targetSdkVersion 25         versionCode 2         versionName "0.7"         renderscriptTargetApi 18 // support mode not supported 21+         renderscriptSupportModeEnabled true         testInstrumentationRunner      "android.support.test.runner.AndroidJUnitRunner"     }     dexOptions {         javaMaxHeapSize "4g"     }     buildTypes {         release {             minifyEnabled false             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'         }     }     lintOptions {         checkReleaseBuilds false         abortOnError false     }      productFlavors {         companylocal         companymaven     } }  dependencies {       def ext = rootProject.ext;      compile fileTree(include: ['*.jar'], dir: 'libs')     compile "com.android.support:appcompat-v7:${ext.supportLibraryVersion}"     compile "com.android.support:design:${ext.supportLibraryVersion}"     compile 'com.romandanylyk:pageindicatorview:0.0.9'     compile "com.jakewharton:butterknife:${ext.butterknifeLibraryVersion}"     annotationProcessor "com.jakewharton:butterknife-compiler:${ext.butterknifeLibraryVersion}"     compile "uk.co.chrisjenx:calligraphy:2.2.0"     compile 'com.android.support:multidex:1.0.1'     // Crashlytics Kit - for crash handling     compile('com.crashlytics.sdk.android:crashlytics:2.5.2@aar') {         transitive = true     }     androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {         exclude group: 'com.android.support', module: 'support-annotations'     })      testCompile 'junit:junit:4.12'     testCompile 'org.robolectric:robolectric:3.0'     testCompile "com.squareup.okhttp3:mockwebserver:${ext.okHttp3LibraryVersion}"     testCompile('com.squareup.assertj:assertj-android:1.1.1') {         exclude module: 'support-annotations'     } } 

Application

public class TestApplication extends Application {      Engine engine;      @Override     public void onCreate() {         super.onCreate();          String privateServerUrlLocal = getString(R.string.server_url);         ProfileLauncher profileLauncher = getProfileLauncher();         LoginLauncher loginLauncher = getLoginLauncher();          // Set up Crash Analytics         final CrashlyticsCore crashlyticsCore = new CrashlyticsCore.Builder().disabled(DEBUG).build();         Fabric.with(this, new Crashlytics.Builder().core(crashlyticsCore).build());          Intent intent = new Intent(this, LogoutService.class);         startService(intent);          CertificatePinner certificatePinner = new CertificatePinner.Builder()                 .add("")                 .add("")                 .build();          engine = new Engine.Builder(privateServerUrlLocal, getString(R.string.other_server_url))                 .setCertificatePinner(certificatePinner)                 .setSDKPartnerSetupManager(getSdkPartnerManager())                 .setLogoutActionHandler(getLogoutActionHandler())                 .setVLocationManager(new VLocationManagerImp())                 .setDebug(DEBUG)                 .addDeepLinkHandler(new ClaimDeepLinkHandler(loginLauncher, profileLauncher))                 .addDeepLinkHandler(new LinkGiftCodeDeeplinkHandler(loginLauncher, profileLauncher))                 .addDeepLinkHandler(new OpenLinkDeepLinkHandler())                 .addDeepLinkHandler(new DetailsDeepLinkHandler())                 .addClaimConfig(new ClaimConfig(false, false, false, false, true))                 .build();         engine.startup(this);     }        @Override     protected void attachBaseContext(Context base) {         super.attachBaseContext(base);         MultiDex.install(base);     }  } 

Manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.package.testapp">  <uses-feature     android:name="android.hardware.camera"     android:required="true" /> <uses-feature     android:name="android.hardware.camera.autofocus"     android:required="false" /> <uses-feature     android:name="android.hardware.camera.flash"     android:required="false" />  <!-- Required for g+ login --> <uses-permission android:name="android.permission.CAMERA" />  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />      <application         android:name=".TestApplication"         android:allowBackup="false"         android:icon="@mipmap/ic_launcher"         android:label="@string/app_name"         android:roundIcon="@mipmap/ic_launcher"         android:supportsRtl="true"         android:theme="@style/AppTheme">          <service             android:name="com.package.companycommon.ui.LogoutService"             android:stopWithTask="true" />          <activity             android:name=".LaunchActivity"             android:screenOrientation="portrait"             android:theme="@style/AppTheme.NoActionBar">             <intent-filter>                 <action android:name="android.intent.action.MAIN" />                 <category android:name="android.intent.category.LAUNCHER" />             </intent-filter>         </activity>          <activity             android:name=".welcome.WelcomeActivity"             android:screenOrientation="portrait"             android:theme="@style/AppTheme.NoActionBar.ClearStatus" />         <activity             android:name=".RegisterActivity"             android:screenOrientation="portrait"             android:theme="@style/AppTheme.NoActionBar.ClearStatus"             android:windowSoftInputMode="adjustResize" />         <activity             android:name=".LoginActivity"             android:screenOrientation="portrait"             android:theme="@style/AppTheme.NoActionBar.ClearStatus"             android:windowSoftInputMode="adjustResize" />         <activity             android:name=".ActivationActivity"             android:screenOrientation="portrait"             android:theme="@style/AppTheme.NoActionBar.ClearStatus"             android:windowSoftInputMode="adjustResize" />         <activity             android:name=".AddPhoneNumberActivity"             android:screenOrientation="portrait"             android:theme="@style/AppTheme.NoActionBar.ClearStatus"             android:windowSoftInputMode="adjustResize" />         <activity             android:name=".ForgotPasswordActivity"             android:screenOrientation="portrait"             android:theme="@style/AppTheme.NoActionBar.ClearStatus"             android:windowSoftInputMode="adjustResize" />         <activity             android:name=".GiftHistoryActivity"             android:screenOrientation="portrait"             android:theme="@style/AppTheme.NoActionBar.ClearStatus" />         <activity             android:name="com.package.PartnerLoginHiddenActivity"             android:screenOrientation="portrait"             android:theme="@style/AppTheme.NoActionBar.ClearStatus" />         <activity             android:name=".tutorial.TutorialActivity"             android:screenOrientation="portrait"             android:theme="@style/AppTheme.NoActionBar.ClearStatus" />         <activity             android:name=".CreateNewPasswordActivity"             android:screenOrientation="portrait"             android:theme="@style/AppTheme.NoActionBar.ClearStatus" />         <activity             android:name=".settings.SettingsActivity"             android:screenOrientation="portrait">             <meta-data                 android:name="android.support.PARENT_ACTIVITY"                 android:value=".GiftHistoryActivity" />         </activity>         <activity             android:name=".settings.ExtraSettingsActivity"             android:label="@string/settings"             android:screenOrientation="portrait">             <meta-data                 android:name="android.support.PARENT_ACTIVITY"                 android:value=".settings.SettingsActivity" />         </activity>         <activity             android:name="companyapp.company.NewsActivity"             android:label="@string/notifications"             android:screenOrientation="portrait"             android:theme="@style/AppTheme" />         <activity             android:name=".termsandconditions.CompanyTermsAndConditionsActivity"             android:screenOrientation="portrait"             android:theme="@style/AppTheme" />          <activity             android:name="com.package.companycommon.ui.PhotoViewerActivity"             android:screenOrientation="portrait"             android:theme="@style/AppTheme" />          <activity             android:name="com.package.company.details.CompanyDetailActivity"             android:screenOrientation="portrait"             android:theme="@style/AppTheme" />         <activity             android:name="com.package.company.details.CompanyDetailActivityLocation"             android:screenOrientation="portrait"             android:theme="@style/AppTheme">             <meta-data                 android:name="android.support.PARENT_ACTIVITY"                 android:value="com.package.company.details.CompanyDetailActivity" />         </activity>         <activity             android:name="com.package.company.ClaimActivity"             android:theme="@style/AppTheme.NoActionBar"             tools:replace="android:theme" />     </application>  </manifest> 

9 Answers

Answers 1

This means your multiDex does not work properly so some files are missing. I think android 5.0 has the different way to use the multiDex. Did you override something in your Aplication class?

Answers 2

Try removing compile 'com.android.support:multidex:1.0.1'. The Google doc says

Therefore, if your minSdkVersion is 21 or higher, you do not need the multidex support library.

I am by no means sure if this helps, but it may be worth trying.

Answers 3

For some reason, this class is not in your main dex anymore.

Declare the class in the main-classes list, using multiDexKeepFile (listing the classes in gradle) or multiDexKeepProguard (pointing to a specific proguard file for the main classes).

Answers 4

Try enabling Progaud and disabling multidex.

You'll not only fix this problem, but you'll have a smaller apk with faster install and run times.

Note, If you need help with this just leave a comment and we can work it out.

  • Ok, so its not Progaurd or MultiDex

The error is that com.package.Application is missing. None of the code you posted (or the manifest) contains a reference to that class. Where are you defining com.package.Application? and if you aren't where in your project is it being referenced? (I'd do a project wide search for "com.package.Application" to unravel this.)

Answers 5

try giving full path in manifest-

  <application         android:name=".TestApplication" 

Also delete the build folder manually-sometimes clean doesn't work.Also uninstall the app manually and start.

Answers 6

I have made demo from your code and configuration and its working in below marshmallow

Download and check it and compare with your code. And one more thing how you have created project with package name com.package.testapp. I am not able to create project with same package name

Answers 7

Create multidex-config.txt to keep this classes in the primary DEX file:

com/package/Application.class com/package/TestApplication.class com/package/testapp/welcome/TestClaimApplication.class 

Add multiDexKeepFile to android.buildTypes.release section of your build.gradle like this:

android {     buildTypes {         release {             multiDexKeepFile file 'multidex-config.txt'         }     } } 

Answers 8

Do you need multidex enabled? I have always run into issues with it. I always understood multidex to be used as a last resort if you are still hitting the 65k method limit. If you are not running into this method limit, you do not need multidex. If you are running into this limit, I would suggest using progaurd to remedy the issue first. If you are still above the method limit even after using proguard, then use multidex.

Answers 9

You need to add your android:name with complete path like this.

android:name="android.support.multidex.MultiDexApplication"  

And your TestApplication should extend MultiDexApplication.

According to the documentation, please refer if need more details. MultiDex Documentation

Read More

Saturday, October 1, 2016

How to close ACTION_USAGE_ACCESS_SETTINGS intent when user click correct target application?

Leave a Comment

I am using Intent ACTION_USAGE_ACCESS_SETTINGS in setting (Settings->Security->Apps with usage access) to use UsageStatsManager in the Lollipop version.

 public static final int MY_PERMISSIONS_REQUEST_PACKAGE_USAGE_STATS = 1;   if(!hasPermission()){                 startActivityForResult(                         new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS),                         MY_PERMISSIONS_REQUEST_PACKAGE_USAGE_STATS);             } 

First, onCreate() will check the permission for the app. and turn on the Intent if the app has no permission (does not check)

@TargetApi(Build.VERSION_CODES.LOLLIPOP) private boolean hasPermission() {     try {         PackageManager packageManager = getApplicationContext().getPackageManager();         ApplicationInfo applicationInfo = packageManager.getApplicationInfo(getApplicationContext().getPackageName(), 0);         AppOpsManager appOpsManager = (AppOpsManager) getApplicationContext().getSystemService(Context.APP_OPS_SERVICE);         int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName);         return (mode == AppOpsManager.MODE_ALLOWED);      } catch (PackageManager.NameNotFoundException e) {         return false;     } } 

My question is that I want to close the setting window, if the user chooses (check) in target app, otherwise, it will show a message about application name to guide the chosen of the user. How can I do it? Thank you. I think it will do in onActivityResult function

@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {     if (requestCode == MY_PERMISSIONS_REQUEST_PACKAGE_USAGE_STATS){         ...     } } 

I refer the link Check if my application has usage access enabled, but it just checks enable of the app.

1 Answers

Answers 1

AppOpsManager has another interesting method:

[void startWatchingMode (String op, String packageName, AppOpsManager.OnOpChangedListener callback)](https://developer.android.com/reference/android/app/AppOpsManager.html#startWatchingMode(java.lang.String, java.lang.String, android.app.AppOpsManager.OnOpChangedListener))

from documentation:

Monitor for changes to the operating mode for the given op in the given app package.

Basically this is what you expect -> react on permission to read package usage stats switch change.

What you need to do is check the allowance state and if it is not granted, open the Settings and create a listener:

private boolean hasPermissionToReadNetworkHistory() {     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {         return true;     }     final AppOpsManager appOps = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);     int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,             android.os.Process.myUid(), getPackageName());     if (mode == AppOpsManager.MODE_ALLOWED) {         return true;     }     appOps.startWatchingMode(AppOpsManager.OPSTR_GET_USAGE_STATS,             getApplicationContext().getPackageName(),             new AppOpsManager.OnOpChangedListener() {                 @Override                 @TargetApi(Build.VERSION_CODES.KITKAT)                 public void onOpChanged(String op, String packageName) {                     int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,                             android.os.Process.myUid(), getPackageName());                     if (mode != AppOpsManager.MODE_ALLOWED) {                         return;                     }                     appOps.stopWatchingMode(this);                     Intent intent = new Intent(MainActivity.this, MainActivity.class);                     intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);                     getApplicationContext().startActivity(intent);                 }             });     requestReadNetworkHistoryAccess();     return false; }  private void requestReadNetworkHistoryAccess() {     Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);     startActivity(intent); } 

Be careful and remove the listener calling the method:

void stopWatchingMode (AppOpsManager.OnOpChangedListener callback)

The example above is just opening main application activity. However you might add any behaviour:

  • pass extra intent parameter to inform just opened activity to show dialog to user
  • Start background service to show toast, that user must grant the permission.
  • etc...

Check out this repository, as it demonstrates this case and the overall usage of NetworkStats.

Read More

Thursday, May 5, 2016

Styling a AppCompatButton in v21 to have no shadow and corner radius of zero

Leave a Comment

I have a AppCompatButton defined in a XML layout, and I have set a theme for it like this:

android:theme="@style/CustomAccentOverlay"

And I have set:

android:stateListAnimator="@null"

to remove the shadow. I have two problems with this.

The height of the button is deducted the height of the shadow, even though the shadow is not shown. Should I remove the shadow in some other way, or how do I fix this?

The button has rounded corners, and I want the corners to be sharp. I can not set a background on the button, because I want to keep the standard ripple effect and that goes away if I set a background (at least I don't know how to keep it if I set a background). I have tried setting

<item name="android:bottomLeftRadius">0dp</item>

and all the other corners to the CustomAccentOverlay theme and also its corresponding style, but it does not work. How can I set the corner radius to zero on my button?

Thank you
Søren

4 Answers

Answers 1

It really sounds like you want to use a clickable TextView rather than a Button. TextView by default will not have shadow and has sharp corners and you can attach a click listener to it. Remember, Button is just a fancy TextView with a lot of visual add-ons to it, and it sounds like you want to remove a lot of it.

If you want to keep the ripple on the TextView and define your own background, set android:foreground="?attr/selectableItemBackground"

Answers 2

First question:How to remove shadow of a button?

Here is the answer: Just add this attribute to your button

android:stateListAnimator="@null" 

Second question: How to make the corner of button sharp without losing the standard ripple effect. Here is the answer: But first you have to make two drawble file with same name but one for below api 21 and one for api > 21 because the ripple is only available only api > 21.So now I am showing how to create that.Read the following text carefully

Right click on the drawble folder and choose new and "Drawble resource file" and hit next then name the drawble whatever you like and press ok.Then again right click on the drawble folder and choose new and "Drawble resource file" and hit next and name the drawble exactly what you named the previous drawble folder but this time at the bottom you can see a section called "available qualifiers".Go to this section and at the very bottom you can see "Version",click it and then you can see a arrow icon at the right,click it then in the "Platform api level" add 21 and then press ok.And now if you expand drawble folder you can see two file of your created drawble file.Once for api that is below 21 and once for upper 21.Open drawble file that you have created and make sure you open that have "(v21)" at the last.Now delete everything from there and add the following code

<?xml version="1.0" encoding="utf-8"?> <ripple android:color="?attr/colorControlHighlight" xmlns:android="http://schemas.android.com/apk/res/android">  <item>     <shape>         <corners android:radius="0dp"/>         <solid android:color="#D6D7D7"/>     </shape> </item>  </ripple> 

And add this attribute to your button

android:background="@drawable/youdrawblefilethatyouhavecreated" 

And now if you run your application you can see that there is no shadow and your button has sharp corner and if you click the ripple shows up.

Lastly,your button look something like this

<android.support.v7.widget.AppCompatButton     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:text="New Button 1"     android:background="@drawable/yourcreatddrawblefile"     android:stateListAnimator="@null"/> 

Hope this help!

Answers 3

Use the following code for the Button.

<android.support.v7.widget.AppCompatButton android:layout_width="200dp" android:layout_height="200dp" android:text="Button" android:stateListAnimator="@null" android:elevation="0dp" android:background="@android:color/darker_gray" android:foreground="?attr/selectableItemBackground" /> 

I will explain the attributes.

  1. android:elevation="0dp" and android:stateListAnimator="@null". No shadow for the button.

  2. android:background . Set the desired color as background. It removes the rounded corners.

  3. android:foreground="?attr/selectableItemBackground" . It gives the ripple effect when the button is pressed.

Update 1:

It seems like android:foreground attribute for View works from API 23. For below APIs, create a drawable with ripple in drawable-v21 folder and set it as background to the button,

<ripple     xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     tools:ignore="NewApi"     android:color="@color/ripple_color">      <item android:drawable="@color/normal_state_button_background_color"/>  </ripple> 

For pre Lollipop versions, create a drawable with selector in drawable folder with the same name.

<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android">     <item android:drawable="@drawable/pressed_color"           android:state_pressed="true" />     <item android:drawable="@drawable/focused_color"           android:state_focused="true" />     <item android:drawable="@drawable/normal_color" /> </selector> 

Answers 4

Use this code

 <android.support.v7.widget.AppCompatButton     android:layout_width="match_parent"     android:layout_height="50dp"     android:background="@color/colorAccent"     android:text="@string/button" /> 
Read More

Sunday, April 24, 2016

Android SDK Add-On hidden class

Leave a Comment

I need to export a hidden class through a SDK Add-On in Android Lollipop. I'm able to export non-hidden classes. After unsuccessfully trying the "usual way" I thought the problem was due to the @hide tag. So I decided to try the "dirty" way of getting rid of the @hide keyword responsible to hide the class (even if that would obviously break compatibility with the standard API). After removing the @hide keyword and building the class with #include(BUILD_JAVA_LIBRARY) in Android.mk, the Java library Jar file is empty. So I have two questions:

  1. Why the Jar file is empty even if the DEX file includes the class?
  2. How do I achieve the same result without removing the @hide keyword?

Thank you.

Note: I have used these resources as references/documentation: http://elinux.org/images/5/5c/Build_and_Distributing_SDK_Add-Ons.pdf https://newcircle.com/s/post/1571/exploring_sdk_add_ons_for_android_devices_larry_schiefer_video

0 Answers

Read More