switching between dialog and activity based on device size - android

In any application the add/edit will be comparatively having lesser inputs. I have seen that the application, esp., calendar, are using clever strategy to show these as simple dialog, so that the user may not notice that there is empty space in the designed form
As shown below
My question is, how to make it happen?

What I'm doing is I extend DialogFragment:
public class AboutFragment extends DialogFragment { ... }
I also have an activity that contains that fragment. And when the dialog/activity needs to be called, this method decides how to display it:
public static void showAbout(Activity parent) {
if (isTablet) {
AboutFragment aboutFragment = AboutFragment.newInstance();
aboutFragment.setStyle(DialogFragment.STYLE_NORMAL, R.style.DialogTheme);
DialogUtils.showDialog(parent, aboutFragment);
} else {
Intent aboutIntent = new Intent(parent, AboutActivity.class);
parent.startActivity(aboutIntent);
}
}
How to decide whether it is a tablet, is totally up to you.
This technique is explained in the documentation.

In my opinion the best approach here is to use
<!-- Theme for a window without an action bar that will be displayed either full-screen
on smaller screens (small, normal) or as a dialog on larger screens
(large, xlarge). -->
"android:Theme.Holo.Light.DialogWhenLarge.NoActionBar"

The best/easiest solution I've found is to always use an Activity, and based on screensize (and version), change your Theme parent.
in res/values/themes.xml
<style name="Detail.Theme" parent="#android:style/Theme.Holo.Light" >
...
</style>
and in res/values-large/themes.xml
<style name="Detail.Theme" parent="#android:style/Theme.Holo.Light.DialogWhenLarge" >
...
</style>

use Context.setTheme method to set them programmetically. As the doc says
this should be called before any views are instantiated in the Context
(for example before calling.
So, to switch between themes need to call setTheme before onCreate
public void onCreate(Bundle savedInstanceState) {
// check screen size
setTheme(dialogTheme);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}

As #StinePike answered, setting a dialog theme programatically doesn't do any use (to me), as it shows a wierd black screen behind the dialog, rather than a dimmed background (as shown in the question). This is obviously a bug.
Instead of trying to set it programatically, or in style.xml, and pretty much everywhere except for AndroidManifest.xml, I did the reverse, which has worked for me.
(the solution which I took from the marvelous solution of the above issue)
The simplest solution (that works) as follows:
1. Make the activity a dialog by default through AndroidManifest.xml:
e.g., in the AndroidManifest.xml:
<activity
android:name="com.example.MyActivity"
android:label="#string/title_activity_mine"
android:theme="#android:style/Theme.DeviceDefault.Dialog">
...
</activity>
2. On starting the activity, set the theme to default if device is not a tablet.
if (!(isTablet(this)) {
setTheme(defaultTheme);
}
super.onCreate(savedInstanceState);
...
Note:
solution will work with custom styles defined in style.xml.
Ref:
How to detect device is Android phone or Android tablet?
Dialog with transparent background in Android
Issue 4394 - android - setTheme() does not work as expected
PS: final app on tablet and phone is as follows:

Use a DailogFragment and then control how its shown with setShowsDialog()

Related

Remove default Splash Screen from Android 12 (Example)

Latest Beta version of Android SDK showcasing Default Splash Screen on every app running on Android 12 (Emulator), As per the requirements, we already have our own Splash Screen.
If anyone have worked on it, let me know how to disable/remove it (preferred to have and example code).
There is no direct API to disable the default splash screen but we can handle this with some workarounds.
Approach 1:
Add <item name="android:windowIsTranslucent">true</item> to your style
<style name="Theme.RemoveSplashScreenTheme" parent="#style/BaseTheme">
<item name="android:windowIsTranslucent">true</item>
</style>
Apply this to splash screen Activity.
<activity
android:name="com.test.SplashScreenActivity"
android:launchMode="singleInstance"
android:theme="#style/Theme.RemoveSplashScreenTheme"
android:noHistory="true" />
this will replace the default splash screen with a transparent screen. This workaround will eliminate the 2 splash screen issue if the app already has one.
But it will make the system splash screen invisible and it may look like the app is not responding. If anyone facing this issue then follow the next workaround.
Approach 2:
So we can resolve this issue by suspending the app to draw an existing splash screen and show the system splash screen until the app is ready.
private void setupOnPreDrawListenerToRootView() {
View mViewContent = findViewById(android.R.id.content);
mViewContent.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
Log.v("onPreDraw","onPreDraw called");
if (isAppInitialized) {
mViewContent.getViewTreeObserver().removeOnPreDrawListener(this);
startActivity(new Intent(this, MainActivity.class));
return true;
} else {
// The content is not ready; suspend.
return false;
}
}
});
}
Here we need to update isAppInitialized to true once the app is ready then we can remove the listener and launch the MainActivity until then it will hold the. app to draw an existing splash screen and execute all the app initializations.
I believe it’s impossible, though I very hope I’m wrong.
The docs does not mention anything about disabling it and it’s automatically being added to all apps.
I’m running Android 12 beta 2.1 on my Pixel 5 device and a lot of my apps have double splash screen because of it.
I recommend giving up migrate your code to the new API and make sure your code is compatible for Android 11 devices and below.

Dynamically show Activity as dialog

I have an Activity that I have already implemented sometime ago.
It involves around making a in app purchase, so all the logic is relatively self contained. it doesn't need to care about anything else.
Now, i wish to make that Activity to optionally show up in a dialog in some other activity. Is there a quick way to do that? I still need to keep the old behavior however, where the activity show up as a regular screen.
So is there someway that I could launch the activity with that make it show up as a dialog?
Thanks
You cant show activity as dialog.
Your options are:
1: Open the other activity with some boolean extra like "showDialog", true
Intent intent = new Intent(this, OtherActivity.class);
intent.putExtra("showDialog", true);
and in the other activity in (for example) onCreate:
Boolean showDialog = getIntent().getExtras().getBoolean("showDialog");
if (showDialog) {
// Code to show dialog
}
2: Create a DialogFragment and show it in your original activity. This custom DialogFragment you can use on both activities
https://guides.codepath.com/android/Using-DialogFragment
Probably your cleanest option depending on how complex your Activity is, is to create a new DialogFragment based on your current activity.
A DialogFragment is basically a Fragment, so has a relatively similar set of lifecycle callbacks to your Activity so it shouldn't be too difficult to re-work as a DialogFragment.
If the in-app purchase framework has specific callback requirements with an Activity then you will need to take that into account.
Another separate option would be to mock the appearance of a Dialog, by creating an Activity that may be transparent around the border of the main content.
Just Inflate the layout one button click on onCreate Method.
WhAT I WILL SUGGEST IS try alert box and in place of normal layout inflate you activity layout .
these might help
The easiest way to do that is to apply a dialog theme to the activity:
<activity android:theme="#style/Theme.AppCompat.Dialog" />
Or in the code:
#Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.Theme_AppCompat_Dialog);
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
}
You can customize parameters of the theme in styles.xml, e.g. dim enabled/disabled, click outside behavior.
The crucial point is to perform setTheme() before super.onCreate(), because Theme is immutable, once set through super.onCreate() it cannot be mutated later.

How to change view for multiple window display in Android N? How to check application is in multiwindow or not?

How can we give separate layout or separate activity for Multiple window ?
eg. I have checked below things with help of android developer site
<activity android:name="com.configure.it.MyScreen">
<layout android:defaultHeight="400dp"
android:defaultWidth="200dp"
android:gravity="top|end"
android:minimalSize="300dp" />
</activity>
by declaring above things it affect how an activity behaves in multi-window mode.
But how can I show different layout if my particular screen is activated on Multiple-Window ?
From the Android Developer link .
To make changes in UI or separate layout which should be used on Multiple-window activate.
We can check if activity is in Multiple-window by following way
From activity Activity.isInMultiWindowMode() Call to find out if the activity is in multi-window mode.
eg. To check in Activity if its multiple window than header(or any view should have Red background color if its not in multiple window thn it should be Green background color)
headerView.setBackgroundColor(inMultiWindow()?Color.RED:Color.GREEN);
using inMultiWindow() replacing Fragment is also possible
To get Callback on Multiple-Window Activation.
From Activity onMultiWindowChanged method is available to handle runtime changes on this method callback.System will give callback on this method whenever the activity goes into or out of multi-window mode with boolean value.With the help of sample link & android developer link
#Override
public void onMultiWindowChanged(boolean inMultiWindow) {
super.onMultiWindowChanged(inMultiWindow);
headerView.setBackgroundColor(inMultiWindow ? Color.RED : Color.GREEN);
// here we can change entire fragment also.
//If multiple window in than seperate and for multiple window out different
}
Will keep updating if I get anything else.
isInMultiWindowMode() is added in API 24 to check device is in Multi window Mode or not, it returns a boolean value. whenever device goes to Multi window Mode it triggers onConfigurationChanged() method.
you will need to manually update your Views, Reload resources, etc... in onConfigurationChanged() based on Landscape and portrait mode.
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
{
//do something (Update your views / Reload resources)
}else{
}
}
In Manifest.xml
<activity
android:name=".yourActivity"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
/>
For further reference check with Multi-Window Support Google Dev and MultiWindow Medium Corp

Showing DialogFragment without the calling Activity as background

I am using the AlarmManager to pass a PendingIntent to my BroadcastReceiver after, say, 5 minutes. Now, I want to show a DialogFragment to the user, on top of whatever app the user might be using when the alarm goes off. For example, if the user is using Chrome when the alarm goes off, my DialogFragment should popup ABOVE the user's Chrome window.
What I am ending up with instead, is the DialogFragment being shown with a blank activity of my app as the background (as in the following pic)
http://i.stack.imgur.com/Vz9IZ.png
This is the code I am using in my BroadcastReceiver, to launch an FragmentActivity first :
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
Intent hardReminderIntent = new Intent(context, AlarmHardActivity.class);
hardReminderIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(hardReminderIntent);
}
}
Next, from this activity, I am popping up the DialogFragment :
public class AlarmHardActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
AlarmHardDialog editNameDialog = new AlarmHardDialog();
editNameDialog.show(fm, "fragment_dialog");
//setContentView(R.layout.activity_alarm_hard);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
//getMenuInflater().inflate(R.menu.activity_alarm_hard, menu);
return true;
}
}
My questions :
I could not find a way to call getSupportFragmentManager directly from the onReceive in my BroadcastReceiver, and thus assumed that the only way to obtain a dialog, would be to first call a 'dummy' activity, that creates the dialog. Is there a better way to do this?
Irrespective of whether or not my approach was correct, I expected that since there is no call to setContentView(..) in AlarmHardActivity, there would be no UI rendered for it. Is my understanding wrong? I also tried calling setContentView(..) and then marking the layout to have Theme.NoDisplay and android:alpha="0", but to no avail.
Any help will be much appreciated. Thanks!
Instead of showing dialog on the activity, better alternative will be making activity look like dialog by using dialog theme and setting margin of all sides to desirable dp, so that activity get shrieked to dialog box size.
For few examples look at these posts:
Android Activity as a dialog
Android: how to create a transparent dialog-themed activity
How to set a dialog themed activity width to screen width?
To your questions:
Fragments can be attached only to Activity (ActivityFragment). So yes, you need dummy Activity for this.
Use the invisible theme #android:style/Theme.Translucent.NoTitleBar, calling setContentView isn't necessary. But this theme isn't Holo compatible (in dialog you would have old Android look). I solved this with custom theme (I use this from ICS, but it should work from HONEYCOMB):
<style name="InvisibleTheme" parent="#android:style/Theme.Holo.Light">
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">#android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">#null</item>
<item name="android:windowIsTranslucent">true</item>
<!-- Note that we use the base animation style here (that is no animations) because we really have no idea how this kind of activity will be used. -->
<item name="android:windowAnimationStyle">#android:style/Animation</item>
</style>
It is impossible to show this dialog without Activity. You can try to run your app like you have on your screenshoot, but with transparent background and hidden ActionBar. But i have never tried to do that so I'm not sure if it will work.

Implementing user choice of theme

I want to give the user the choice between a few different themes, and was wondering if this is an alright way of doing things. I did a little test with this method and it worked, but I think there may be better ways and think it may cause some problems later on, so wanted to ask.
I was thinking of creating a different layout for each theme, and in onCreate just having a switch for the setContentView() method. I'd load a saved SharedPreference value (integer) first and depending on what that value was display the corresponding layout. Obviously the user could change the SharedPreference value with a button or something.
As these layouts would be basically the same but with different colours, I'd want to use the same IDs for my TextViews and other Views in each layout file. My main question is would this cause problems?
Sorry for the wall of text with no code. I'd just like to get a general idea of good practice for this situation. Thanks in advance.
I actually have this feature in my application and additionally, I allow users to change theme at runtime. As reading a value from preferences takes some time, I'm getting a theme id via globally accessible function which holds cached value.
As already pointed out - create some Android themes, using this guide. You will have at least two <style> items in your styles.xml file. For example:
<style name="Theme.App.Light" parent="#style/Theme.Light">...</style>
<style name="Theme.App.Dark" parent="#style/Theme">...</style>
Now, you have to apply one of these styles to your activities. I'm doing this in activitie's onCreate method, before any other call:
setTheme(MyApplication.getThemeId());
getThemeId is a method which returns cached theme ID:
public static int getThemeId()
{
return themeId;
}
This field is being updated by another method:
public static void reloadTheme()
{
themeSetting = PreferenceManager.getDefaultSharedPreferences(context).getString("defaultTheme", "0");
if(themeSetting.equals("0"))
themeId = R.style.Theme_Light;
else
themeId = R.style.Theme_Dark;
}
Which is being called whenever preferences are changed (and, on startup of course). These two methods reside in MyApplication class, which extends Application. The preference change listener is described at the end of this post and resides in main activity class.
The last and pretty important thing - theme is applied, when an activity starts. Assuming, you can change a theme only in preference screen and that there's only one way of getting there, i.e. from only one (main) activity, this activity won't be restarted when you will exit preference screen - the old theme still will be used. Here's the fix for that (restarts your main activity):
#Override
protected void onResume() {
super.onResume();
if(schduledRestart)
{
schduledRestart = false;
Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage( getBaseContext().getPackageName() );
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
}
scheduledRestart is a boolean variable, initially set to false. It's set to true when theme is changed by this listener, which also updates cached theme ID mentioned before:
private class ThemeListener implements OnSharedPreferenceChangeListener{
#Override
public void onSharedPreferenceChanged(SharedPreferences spref, String key) {
if(key.equals("defaultTheme") && !spref.getString(key, "0").equals(MyApplication.getThemeSetting()))
{
MyApplication.reloadTheme();
schduledRestart = true;
}
}
sp = PreferenceManager.getDefaultSharedPreferences(this);
listener = new ThemeListener();
sp.registerOnSharedPreferenceChangeListener(listener);
Remember to hold a reference to the listener object, otherwise it will be garbage colleted (and will cease to work).
If you are using Material Components themes and followed Light and Dark theme guidelines then you can do it from AppCompatDelegate. These themes can be changed/applied at run time without restarting your application.
private fun handleThemeChange(theme: String) {
when (newTheme) {
getString(R.string.light) -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
getString(R.string.dark) -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
getString(R.string.system) -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
}
You can also change dynamically theme using:
ContextThemeWrapper w = new ContextThemeWrapper(this, <newTHEMEId>);
getTheme().setTo(w.getTheme());
Before onCreate for each activity.
It does work if you do it this way, and I don't think it would cause any problem, but it seems like a lot of hassle (you have to multiply all your layouts by all the themes you want to add. If later you want to modify a resource in a layout, you'll have to modify it in all the themes. You're definitely bound to forget one)
Why not using the Styles and Themes feature of Android?
They can be applied to the whole activity easily:
<activity android:theme="#style/my_theme">
So that when you detect a change in the SharedPreferences value you use (button on a preference activity, or something) you can just switch the style. Or better, you can set the style to read your preference value at runtime (when creating the activity) and apply the correct style/theme accordingly.

Categories

Resources