How to change the screen orientation during automated testing? - android

I am testing my Android application using ActivityInstrumentationTestCase2, and I need to test that the screen orientation change works correctly. However, I cannot find any way to cause an orientation to occur. What am I missing?

Check this example where I tried extending Android ActivityInstrumentationTestsCase2 to use different screen orientations: iliasbartolini / AgileDayConferenceApp
Basically you need to change the Resources configuration. I found this example here: Tip for unit-testing: loading Resources for a specific screen orientation/
Resources res = getInstrumentation().getTargetContext().getResources();
Configuration oldResourcesConfiguration = res.getConfiguration();
Configuration newConfiguration = new Configuration(oldResourcesConfiguration);
newConfiguration.orientation = configurationOrientation;
res.updateConfiguration(newConfiguration, res.getDisplayMetrics());
Here is a dummy Landscape test example on how to use it.
It actually only checks that the Landscape layout and resources loaded by the activity are not broken: don't know if there are better ways to do it.
And here the Portrait test

Related

Preventing android 12 system font size from affecting in-app font size (crash)

I am currently facing a problem - for the third time -.-. We are developing an app with xamarin. So far so good. But on Android there is a little issue. Since Samsung decided it had to sell a "Fold" smartphone, our client came up with a little problem. I don't know if this only occurs because he is not the youngest anymore or its because of the smartphone. In the end it doesn't matter..
To stop beating around.. Our Android app changes the font size if the system font size gets changed. This leads to UI bugs in the whole app. Of course we could apply our complete app to be more responsive. But to be honest, our target group are between 15 and 25. So in 99.9% of the time, the user has not changed the system font size.
I already figured out/found a solution in the internet.
So I added this to my MainActivity.cs in my Android-project.
public override Android.Content.Res.Resources Resources
{
get
{
//Prevent system font size from affecting in -app font size
Android.Content.Res.Configuration config = base.Resources.Configuration;
if (config == null)
config = new Android.Content.Res.Configuration();
config.FontScale = 1f;
return CreateConfigurationContext(config).Resources;
}
}
Til today it worked fine but then i updated my simulator to Android 12 and I am facing a new problem with this code. When I want to play a video or open a image in our app, the app crashes with a NullPointerException. If I delete this code, the system font size won't be ignored anymore.
Has anyone faced a similar problem and maybe already found a solution?
So I added this to my MainActivity.cs in my Android-project.
public override Android.Content.Res.Resources Resources
{
get
{
//Prevent system font size from affecting in -app font size
Android.Content.Res.Configuration config = base.Resources.Configuration;
if (config == null)
config = new Android.Content.Res.Configuration();
config.FontScale = 1f;
return CreateConfigurationContext(config).Resources;
}
}
Up to Android 11 it worked just fine. But since Android 12 I can't play videos or open images in our app.
You can try to put the following code into the MainActivity to prevent android system font size from affecting in-app font size.
protected override void AttachBaseContext(Context #base)
{
Configuration configuration = new Configuration(#base.Resources.Configuration);
configuration.FontScale = 1.0f;
ApplyOverrideConfiguration(configuration);
base.AttachBaseContext(#base);
}

Android - How to force Portrait orientation on phone and tablets, but Landscape only on Android TV?

I am developing an Android application in portrait mode like this:
[ScreenOrientation = Android.Content.PM.ScreenOrientation.Portrait)]
public class MainActivity : AppCompatActivity
{
// ...
}
It is working fine on all phone and tablet devices, both physical and emulators.
On the other hand, it is working very bad on Android TV emulators. The screen is being cut in half and the application is unusable. However landscape orientation seems good for Android TV format and works fine.
So my question is: is there any way to keep portrait orientation for phone and tablets and use landscape for TV?
I tried to use resources and size qualifiers (like a bool threshold value in res/values-sw1200dp) and then request an orientation change with RequestedOrientation = Android.Content.PM.ScreenOrientation.Landscape; but I'm afraid to include also high definition tablets in this way.
Does anyone have a better solution? I am developing in Xamarin.Android, but any solution in Android Studio would also be welcome.
Found a solution myself. I do not want to use sizes as some tablets have better resolution than TVs.
var res = Application.Context.Resources;
if (res.DisplayMetrics.DensityDpi == Android.Util.DisplayMetricsDensity.Tv ||
res.Configuration.UiMode.HasFlag(Android.Content.Res.UiMode.TypeTelevision))
{
RequestedOrientation = Android.Content.PM.ScreenOrientation.Landscape;
}
This is basically the code. Then I used other code tricks like global vars as activity was being recreated if this was called inside onCreate method. Putting this on manifest.xml was not enough.
android:configChanges="orientation|screenSize"

Titanium android different orientation lock between tablet and phone

I'm using Titanium, my app supports tablets and phones. For phones I need to use PORTRAIT orientation anche for tablets LANDSCAPE.
I tried to configure android:screenOrientation="nosensor" in tiapp.xml importing all activities from AndroidManifest.xml and orientationModes : [Ti.UI.LANDSCAPE_LEFT] in window configuration in tablet case, but I have no results. All orientations are active.
Anyone can help me?
This should be pretty forward with following points:
Since you need to change orientations at runtime, you cannot control it from tiapp.xml unless you create separate builds for phones and tablets which I believe is not the case.
Leave tiapp.xml as default and do not set any orientation there.
Use below snippet for handling it inside app.tss file.
"Window[if=Alloy.isTablet]" : {
orientationModes : [Ti.UI.LANDSCAPE_LEFT, Ti.UI.LANDSCAPE_RIGHT]
}
"Window[if=Alloy.isHandheld]" : {
orientationModes: [Ti.UI.UPSIDE_PORTRAIT, Ti.UI.PORTRAIT]
}
This solution will work only if you create Window controllers using XML, not by using Classic JS.
Double check your code to not to set orientations anywhere else to avoid any issues.

Set Locale from App - Back Button Issue

I am working on Language setting on my app. I was able to change the locale from my Main Activity through the use of
Resources resources = getResources();
Configuration configuration = resources.getConfiguration();
DisplayMetrics displayMetrics = resources.getDisplayMetrics();
configuration.setLocale(new Locale("ar"));
resources.updateConfiguration(configuration,displayMetrics);
recreate();
Everything worked fine but I noticed that the back button did not change its direction to RTL:
This is my expected behaviour when I set the language to a RTL language:
Is this possible?
Changing the navigation bar's direction means that the app will change the Locale of the device. Such a thing is similar to setting the device language in the language setting of the device since a Locale defines the language and direction (rtl or ltr) of the views to support the language. Since you're only changing the Locale of your Context in the app, it will not affect the Context of the other apps on the device and the system apps/components (launcher, navigation bar, status bar, etc...). Hence the navigation bar will not change and stay unaffected by the change in your app.
Furthermore, to alter the device Locale or any other configuration (font, font size, display metrics, rotation, etc..), the app would need the SET_CONFIGURATION permission to do so. Although it is not stated in the docs, the SET_CONFIGURATION permission can only be given automatically to system apps like the language and display settings. I haven't seen if it can be requested from the user by a third party app but I believe that it cannot be as most of the times in the development of my apps, the permission was being granted using adb shell pm grant command in the command line. Usually I would do that during my tests since my apps also support other languages and would want to make sure that the app performs well in such cases, hence I'd grant it the permission in the command line and let it to change the locale of the device from within the tests.
Try to call this method when you set arabic language:
#TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void forceRTLIfSupported()
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
//HERE CHECK CONDITION FOR YOUR LANGUAGE if it is AR then
//change if it is english then don't
getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
}
}
The direction of the navigation bar (and other parts of the OS, like the Settings), is not related to an app. A user can have a LTR OS with a RTL app. thus changing your app's locale and direction does not affect the underlying OS and the user has to change it manually.

Best Practices for organizing different code for phone and tablet

I'm adapting an existing phone application for tablets. The problem is that there are some small differences in the UI between the phone and the tablet.
For example, on the phone, there is a landing page and then a login page with a cancel button that goes back too the landing page.
On the tablet, the login fragment is on the landing page and the cancel button is removed. This means that I've made a check to see if the device is a tablet and if it is, I dunno find the view of the cancel button.
This seems hacky to me and i was wondering if there was a better way to do this. Thanks.
Tablet or phone ?
First of all you should know on which device you are. An elegant way (in my opinion) is to declare a resource in config.xml :
values/config.xml
<bool name="isTablet">false</bool>
values-sw600dp/config.xml
<bool name="isTablet">true</bool>
Then extends Application and keep the type of device running the app :
public static boolean IS_TABLET = false;
public void onCreate() {
super.onCreate();
MyApp.IS_TABLET = getResources().getBoolean(R.bool.isTablet);
}
Handling differents view
To handle differents view use the differents folders in /res
/layout for phone view
/layout-sw600dp for 7" tablet (you can just use this folder if there is no difference between 7 et 10")
/layout-sw720dp for 10" tablet
Handling code
Two solutions here :
1- The change between views are minor : keep the same activity/fragment and add some condition like
if(MyAPP.IS_TABLET) {
// DO something on tablet
} else {
// Do something on phone
}
2- If tablet and phone are very different create a new activity/fragment with a suffixe like :
HomeActvity => HomeActivityTablet
And add a condition on the loading of this particular view.
You can also works with differents namespace , depending on what give you best architecture.
Exemple
Have a look on the Google IO app's source code

Categories

Resources