AppCompatDelegate.setDefaultNightMode doesn't work on physical device - java

Changing night-light mode perfectly works in my emulator, but when i try to do the same on physical device(xiaomi) I get next exception:
E/ActivityInjector: get life cycle exception
java.lang.ClassCastException: android.os.BinderProxy cannot be cast to android.app.servertransaction.ClientTransaction
at android.app.ActivityInjector.checkAccessControl(ActivityInjector.java:24)
at android.app.Activity.onResume(Activity.java:1859)
at androidx.fragment.app.FragmentActivity.onResume(FragmentActivity.java:456)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1454)
at android.app.Activity.performResume(Activity.java:8050)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4269)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4311)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ClientTransactionHandler.executeTransaction(ClientTransactionHandler.java:57)
at android.app.ActivityThread.handleRelaunchActivityLocally(ActivityThread.java:5353)
Here is my code in activity and presenter where i change mode of my my application:
public class MoviesListActivity extends AppCompatActivity implements MovieListView {
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
if (item.getItemId() == R.id.darkMode) {
presenter.changeToDarkMode();
}
else if(item.getItemId() == R.id.lightMode) {
presenter.changeToLightMode();
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.movie_list);
presenter = new MoviesListPresenter(this, getApplicationContext());
if (presenter.getCurrentMode() == 0) {
presenter.changeToLightMode();
} else {
presenter.changeToDarkMode();
}
}
//Other code...
}
Presenter:
public class MoviesListPresenter {
public void changeToLightMode() {
currentMode = context.getSharedPreferences(Constants.MODE, Context.MODE_PRIVATE);
currentMode.edit().putInt(Constants.MODE, 0).apply();
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
public void changeToDarkMode() {
currentMode = context.getSharedPreferences(Constants.MODE, Context.MODE_PRIVATE);
currentMode.edit().putInt(Constants.MODE, 1).apply();
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
}
public int getCurrentMode() {
currentMode = context.getSharedPreferences(Constants.MODE, Context.MODE_PRIVATE);
return currentMode.getInt(Constants.MODE, 0);
}
}
I will be thankful for any help!

This seem caused by calling Activity.recreate() in Xiaomi's firmware. This problem also happen to my library which recreate the activity to apply the language changing.
See https://github.com/akexorcist/Localization/issues/89
In my case, no app crashing and code working properly. So I skipped this problem.
Related questions
MIUI 11/12 Theme Switch Results in LifeCycleException, ClassCastException
Getting Lifecycle Exception While Recreating The Activity

Related

Android - default dark mode

I want to implement in my app Dark mode. In default I wish it been following by the system, so in Main Activity I've placed:
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
It works fine, but I if user wants to change its mind and select certain option in my app menu to toggle off/on dark mode, activity is restarting and app's still following system rules. How can I change that?
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_color_mode) {
if(AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
else
AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_YES);
return true;
}
Code responsible for option you mentioned, is within onCreate(). Mechanism that allows user to change mode is not within onCreate()
public class MainActivityextends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
}
}
When you explicitly change the dark mode, Android recreates the activity and hence calls onCreate again.
So, after you change the dark mode you won't notice a change, as AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM is called again when onCreate is called by the system.
To make this works you can save a value into SharedPreference that can be checked in onCreate before setting the system dark mode.
This can be a boolean that you can toggle when you want to manually change the dark mode.
Here is a sample
public class MainActivityextends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean isSystem = prefs.getBoolean("IS_SYSTEM", true);
if (isSystem) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_color_mode) {
if(AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
else
AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_YES);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.edit().putBoolean("IS_SYSTEM", false).apply();
return true;
}
}
UPDATE
that works perfect, but when I quit application and then launch again, default system mode is active although I've switched it. Is possible here to make it works in that way?
You can use another SharedPreference boolean to be saved permanently
public class MainActivityextends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean isSystem = prefs.getBoolean("IS_SYSTEM", true);
boolean isNight = prefs.getBoolean("IS_NIGHT", false);
if (isSystem) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
} else if (isNight) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_color_mode) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
prefs.edit().putBoolean("IS_NIGHT", false).apply();
} else {
AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_YES);
prefs.edit().putBoolean("IS_NIGHT", true).apply();
}
prefs.edit().putBoolean("IS_SYSTEM", false).apply();
return true;
}
}

UtteranceProgressListener won't call the functions

I am trying to make a speech powered app, however I have run into a major problem.
My UtteranceProgressListener Class will not call any of the given methods regardless of where I place the Speak method.
Here is my code:
This is my OnCreate Method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
voiceBtn = (Button) findViewById(R.id.startListeningBtn);
voiceBtn.setEnabled(false);
textToSpeech = new TextToSpeech(mContext,new botListener());
}
This is the OnInitListner Imeplementation
public class botListener implements TextToSpeech.OnInitListener{
#Override
public void onInit(int i) {
if(i == TextToSpeech.SUCCESS)
{
int s = textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
#Override
public void onStart(String s) {
Toast.makeText(getApplicationContext(),"Done Speaking",Toast.LENGTH_SHORT).show();
}
#Override
public void onDone(String s) {
Toast.makeText(getApplicationContext(),s,Toast.LENGTH_SHORT).show();
}
#Override
public void onError(String s) {
Toast.makeText(getApplicationContext(),"Done Speaking",Toast.LENGTH_SHORT).show();
}
});
Log.d(TAG,String.valueOf(s));
int result = textToSpeech.setLanguage(Locale.ENGLISH);
if(result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED){
Log.e(TAG,"Language not supported");
Intent installLanguage = new Intent(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installLanguage);
}
Log.d(TAG,"Started Voice Speaker");
}
else{
Log.e(TAG,"initialization failed");
}
}
}
Now, when I press the button, the event that fires is:
public void initVoiceRecog(View v){
//Toast.makeText(mContext,"Clicked",Toast.LENGTH_SHORT).show();
Speak("hello","1");
// does some other things here after that
}
private void Speak(String text,String identifierID){
if(Build.VERSION.SDK_INT>21) {
Bundle params = new Bundle();
params.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,identifierID);
textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, params, identifierID);
}
else{
// ttsMap is a HashMap
ttsMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,identifierID);
textToSpeech.speak(text,TextToSpeech.QUEUE_FLUSH,ttsMap );
}
}
My Question is, after saying hello, it does not fire the OnStart() or the OnError() or the OnDone() methods. Why is this happening?
I tried with the deprecated setOnUtteranceListner() as well, same result. It does not fire any of the methods, the Toasts don't show up.
Please tell a fix or a workaround for this.
The Devices I tried on are:
API 19 Micromax Canvas Nitro
API 21 Samsung S4
API 23(Marshmellow) ASUS Zenfone
I finally figured out why the callbacks were not working. Turns out, they were working and calling on a separate thread. So to execute the normal functionality, call the functions in the 'Activity.this.RunOnUiThread' and put this in the call back fuctions.

Android Setting Up Splash Screen(Activity) Like Iphone Part1

I have three images with me and i want them to appear on first layout xml like a splash view so that they can be viewed only once i.e that activity will be called only once when app get's installed or if app get's a new update otherwise app should always start from the Second activity, i don't know how should i begin with this :
Can any one tell me any idea how this can be done.
To show splash for only once.
Next part of this question is here
Coding will be much appreciated.
Save a flag in the Preferences when you start up the application, after you've done the welcome screen stuff. Check for this flag before you show the welcome screen. If the flag is present (in other words, if it's not the first time), don't show it.
In your activity:
SharedPreferences mPrefs;
final String welcomeScreenShownPref = "welcomeScreenShown";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
// second argument is the default to use if the preference can't be found
Boolean welcomeScreenShown = mPrefs.getBoolean(welcomeScreenShownPref, false);
if (!welcomeScreenShown) {
// here you can launch another activity if you like
// the code below will display a popup
String whatsNewTitle = getResources().getString(R.string.whatsNewTitle);
String whatsNewText = getResources().getString(R.string.whatsNewText);
new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert).setTitle(whatsNewTitle).setMessage(whatsNewText).setPositiveButton(
R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).show();
SharedPreferences.Editor editor = mPrefs.edit();
editor.putBoolean(welcomeScreenShownPref, true);
editor.commit(); // Very important to save the preference
}
}
Try this :
public class MainActivity extends Activity {
private Thread mSplashThread;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.splash);
final MainActivity sPlashScreen = this;
mSplashThread = new Thread() {
#Override
public void run() {
try {
synchronized (this) {
wait(4000);
}
} catch (InterruptedException ex) {
}
finish();
Intent intent = new Intent();
intent.setClass(sPlashScreen, StartNewActivity.class);// <-- Activity you want to start after Splash
startActivity(intent);
}
};
mSplashThread.start();
} catch (Exception e) {
}
}
#Override
public boolean onTouchEvent(MotionEvent evt) {
try {
if (evt.getAction() == MotionEvent.ACTION_DOWN) {
synchronized (mSplashThread) {
mSplashThread.notifyAll();
}
}
} catch (Exception e) {
}
return true;
}
}
you put an Image in splash.xml to show
to do this you have to detect the first launch of your application. To do so you can store a boolean value as #Nirav suggested.
And for the splash screen, You can consider using Fragments and ViewPager to create an activity which will only be shown for the first time

App crashing without reason

I just updated my app on the play store and i started receiving crash reports from people, one was a person i know, so he started helping me to solve this problem, and i discovered that the problem is caused by something i didn't even modify.
The code looks like this
The part that's causing the problem is the bulb.onClickListener
public class Bulb extends Activity {
public boolean isAwake = false;
boolean timerActivated = false;
static ImageView glow;
public static boolean bulbActIsRunning = false;
public void startWake() {
Intent wS=new Intent(getBaseContext(), WakeService.class);
startService(wS);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageButton bulb = (ImageButton) findViewById(R.id.bulb);
ImageButton ghl = (ImageButton) findViewById(R.id.ghl);
glow = (ImageView) findViewById(R.id.glow);
if (WakeService.isAwake) {
glow.setVisibility(View.VISIBLE);
}
else {
glow.setVisibility(View.INVISIBLE);
}
bulb.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startWake();
if (WakeService.isAwake) {
glow.setVisibility(View.INVISIBLE);
}
else {
glow.setVisibility(View.VISIBLE);
}
}
});
ghl.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geekshavelanded.com/"));
startActivity(browserIntent);
}
});
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
glow = (ImageView) findViewById(R.id.glow);
if (WakeService.isAwake) {
glow.setVisibility(View.VISIBLE);
}
else {
glow.setVisibility(View.INVISIBLE);
}
}
#Override
public void onStart() {
super.onStart();
bulbActIsRunning = true;
}
#Override
public void onStop() {
super.onStop();
bulbActIsRunning = false;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
After my friends clicks the bulb button the app crashes without reason, i've put some toast notification at the beginning of the onClickListener to see if it appeared before crashing, but it didn't
The crash reports look like this
java.lang.RuntimeException: Unable to start service com.doublep.wakey.WakeService#41740bb8 with Intent { cmp=com.doublep.wakey/.WakeService }: java.lang.NullPointerException
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2933)
at android.app.ActivityThread.access$1900(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1438)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5454)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1029)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:796)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at android.os.Parcel.readException(Parcel.java:1436)
at android.os.Parcel.readException(Parcel.java:1384)
at com.android.internal.appwidget.IAppWidgetService$Stub$Proxy.updateAppWidgetIds(IAppWidgetService.java:513)
at android.appwidget.AppWidgetManager.updateAppWidget(AppWidgetManager.java:333)
at android.appwidget.AppWidgetManager.updateAppWidget(AppWidgetManager.java:400)
at com.doublep.wakey.WakeService.keepAwake(WakeService.java:86)
at com.doublep.wakey.WakeService.onStartCommand(WakeService.java:48)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2912)
... 10 more
Can anyone see something suspicious?
I didn't even touch the code of this activity when i was updating my app, and everything else works fine, because i can call the service from a widget aswell.
So the problem must be here
I also modified the min SDK from 8 to 7 (but to see if it works i've put it back to 8)
And i compressed some graphics a little bit more to save space
EDIT oh i forgot to say, this happens only to few devices, on most it seems working fine
UPDATE 2 this is the piece of code that caused those issues
AppWidgetManager mgr=AppWidgetManager.getInstance(this);
mgr.updateAppWidget(ToggleWidget.appWidgetId, ToggleWidget.remoteViews);
Please check the parameter to updateAppWidget(). Ether remote view is null or you are setting null bitmap.

Shared preferences don't take effect until Preferences clicked

I'm writing an app for the Sony Smartwatch, using their SDK. Here's part of the main activity:
class SmartTickerActivity extends ControlExtension {
private Handler mHandler;
SmartTickerActivity(final String hostAppPackageName, final Context context, Handler handler) {
super(context, hostAppPackageName);
if (handler == null) {
throw new IllegalArgumentException("handler == null");
}
}
#Override
public void onStart() {
//do some stuff
PreferenceManager.setDefaultValues(mContext, R.xml.preference, false);
}
The problem is that the saved preferences aren't being applied on the Smartwatch when the application launches. Nor are the default preference values from XML. However, if I click on any of the app's preferences on the phone, the saved preference values are immediately applied to the Smartwatch.
Note that the main class has no onCreate() method, and that's throwing me for a loop.
Here's part of the Preference activity:
public class MyPreferenceActivity extends PreferenceActivity {
private OnSharedPreferenceChangeListener mListener = new OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preference pref = findPreference(key);
if (pref instanceof ListPreference) {
ListPreference listPref = (ListPreference) pref;
pref.setSummary(listPref.getEntry().toString());
}
if (pref instanceof EditTextPreference) {
EditTextPreference editTextPref = (EditTextPreference) pref;
pref.setSummary(editTextPref.getText().toString());
}
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preference);
setSummaries();
setTypeface(SmartTickerActivity.mainLayout);
if (previewLayout != null) setTypeface(previewLayout);
// Handle read me
Preference readMe = findPreference(getText(R.string.preference_key_read_me));
readMe.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference readMe) {
showDialog(DIALOG_READ_ME);
return true;
}
});
// Handle about
Preference about = findPreference(getText(R.string.preference_key_about));
about.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference about) {
showDialog(DIALOG_ABOUT);
return true;
}
});
// Handle preview
Preference preview = findPreference(getText(R.string.preference_key_preview_dialog));
preview.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preview) {
showDialog(DIALOG_PREVIEW);
return true;
}
});
}
I'm rather inexperienced at Android development, so the problem might very well have nothing to do whatsoever with the Sony SDK. Can anyone help?
You are correct, the preferences of the official sample extensions are not loaded until the PreferenceActivity is shown for the first time. If you use correct default values when accessing the preferences, this should not be a problem.
If you would like for the preferences to be loaded when the extension is initiated the first time, you could extend the android.app.Application class, and the onCreate method.
For example:
public class MySmartWatchApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
PreferenceManager.setDefaultValues(this, R.xml.app_preferences, false);
}
}

Categories