Simple but serious issue with Tablet programming for android - android

So I'm taking the course by Google "Developing Android Apps" and I am stuck since I ran into a serious problem I can't explain:
See,their idea is to have a different layout file for tablets under the folder res\layout-sw600dp so that if the minimum height/width of the device is 600dips then there will be a different layout inflated.
The only problem is that for some reason that assertion doesn't work, not for their code nor for the simple code i added here,at least not for an AVD tablet (I've used Nexus 10 with api 21).
For example the following code shows "Phone!" on the toast rather than "Tablet!":
public class MainActivity extends AppCompatActivity {
static final String TABLET="Tablet!";
static final String PHONE="Phone!";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String foundDeviceStr;
if(findViewById(R.id.weather_detail_container)==null){
foundDeviceStr=PHONE;
} else{
foundDeviceStr=TABLET;
}
Toast toast=Toast.makeText(this,foundDeviceStr,Toast.LENGTH_LONG);
toast.show();
}
}
When the xml file under the folder layout-sw600dp does have a frame with the id weather_detail_container.
I will add both xml files that I created at the bottom of the email, but you can also try out branch 5.10 from the following Google project- it doesn't load a two panes as it should:
https://github.com/udacity/Sunshine-Version-2/tree/5.10_selected_item, again at least not for any AVD devices (I have a physical android phone but not a physical tablet).
For the question to be complete here are the two xml files:
under the folder layout this is activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="Whatever"/>
</LinearLayout>
and under the folder layout-sw600dp this is activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:divider="?android:attr/dividerHorizontal"
android:orientation="horizontal"
tools:context="com.example.android.sunshine.app.MainActivity">
<!--
This layout is a two-pane layout for the Items master/detail flow.
-->
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:text="Whatever" />
<FrameLayout
android:id="#+id/weather_detail_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="4" />
</LinearLayout>

You need to ask/get the SCREENLAYOUT_SIZE_MASK that is the key...
I have tried ONLY on samsung devices but it was pretty accurate....
Example:
Context myAppContext = ...//load the context here...;
boolean amATablet = (myAppContext.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE;
if (amATablet) {
//Hello Tablet
}else{
//hello Phone
}

OK guys,so I just got a viable answer to my question:
Simply uncheck "enable device frame" in emulator settings!
If you need further assistance you can use this link:
How to remove the device's frame on Android Studio's emulators
Having said all that, I am not sure WHY that works. After all,the definition of this setting is: "Enable a frame around the Android emulator window that mimics the look of a real android device", so that SHOULD change only the looks according to my understanding. So if anyone knows why, please do post a further answer or comment :)

Related

Why there is a difference between my app in a real device and the layout preview in android studio

app description :-
simple app with listView (orientation : horizontal)
the problem is :-
when i run the app on a real device , i found that all views direction get reversed
this is an item on android studio:-
app preview on android studio
but when it run on a real device it look like this
app on a real device
this is my layout (item.xml) code
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="#+id/item_layout_id"
android:padding="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/mag_id"
android:layout_weight="1"
android:text="7.1"
android:textColor="#302f2f"
android:textSize="18sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/country_id"
android:layout_weight="1"
android:text="Egypt"
android:textColor="#302f2f"
android:textSize="18sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/date_id"
android:layout_weight="1"
android:text="July 21,2018"
android:textColor="#302f2f"
android:textSize="18sp"/>
</LinearLayout>
i want to display the same design from android studio preview on the real device
with the same view direction.
so what is the problem and how i can fix this.
This is due to difference between the screen size and display resolution, the layout that you're designing in the studio might look good on that exact screen size or resolution that you've selected in the layout editor, but that might not be the case for every device, your device in this case.
You can refer this thread for more detailed solution to your problem
you should check two or three things:
1- is your ListView parent layout has layoutDirection in XML?
2- have you called the method getWindow().setLayoutDirection(LayoutDirection.RTL) any where in your code?
3- if your list activity or fragment does not have number 2 then you should check your adapter class to see if there is any code written about ItemView direction.
4- if non of this is relevant for you please try changing preview android version and preview size.
hope this helps.

android incorrect layout for tablet in setContentView

I'm working on a toy app which has different layout files for phones and tablets but in tablet mode it doesn't use the correct layout in layout-sw600dp folder. Here are my files contents:
activity_main.xml in layout-sw600dp folder:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:divider="?android:attr/dividerHorizontal"
android:orientation="horizontal"
tools:context="com.example.android.sunshine.app.MainActivity">
<!--
This layout is a two-pane layout for the Items master/detail flow.
-->
<fragment
android:id="#+id/fragment_forecast"
android:name="com.example.android.sunshine.app.ForecastFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
tools:layout="#android:layout/list_content" />
<FrameLayout
android:id="#+id/weather_detail_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="4" />
</LinearLayout>
activity_main.xml in layout folder:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/fragment_forecast"
android:name="com.example.android.sunshine.app.ForecastFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
tools:context="com.example.android.sunshine.app.ForecastFragment"
tools:layout="#android:layout/list_content" />
onCreate method in MainActivity.java:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLocation = Utility.getPreferredLocation(this);
setContentView(R.layout.activity_main);
if(findViewById(R.id.weather_detail_container) != null)
{
mTwoPane = true;
if(savedInstanceState == null)
{
getSupportFragmentManager().beginTransaction().replace(R.id.weather_detail_container, new DetailActivityFragment(),DETAILFRAGMENT_TAG).commit();
}
}
else
{
mTwoPane = false;
}
}
I'm using emulated Nexus 10 to test the app. When the app comes up it shows the single pane layout, the same as phone view. I don't know what is going wrong here.
I also tried with emulated Nexus 7 and still the problem exists.
Amazingly I tried with Samsung Galaxy Note 10.1 API 16 real device and the layout works perfectly. Is there any issue with the emulated device that causes the problem?
EDIT
I suspected that there is something wrong with emulated device and tried to emulate Samsung Galaxy Note 10.1 API 16. The layout works fine on the emulated version of the device too.
I tried to also use API 16 with emulated Nexus 7 but still I got the single pane layout. Is there something wrong with Nexus 7 & 10 with layout-sw600dp folder?
Yes, this is the issue with emulator.
Straight solution - don't use Nexus skin.
I tested various configs: Nexus 9 should work fine.
Almost in all Android courses (topic: fragments, two pane mode) in forums you can find complains about this issue.
SO questions: 1, 2.
There are some questions in the android issue tracker: 1, 2.
The issue is old and there is no official responses.

Layout Rotation & Clipping Behavior prior Android 4.3

Strange behavior when rotating a layout (e.g. a FrameLayout) with an image view inside, on different Android versions.
Take a look at the following piece of XML layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000" >
<FrameLayout
android:layout_width="250dp"
android:layout_height="250dp"
android:background="#ffffff"
android:layout_gravity="center"
android:rotation="15" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="#drawable/bg" />
</FrameLayout>
</FrameLayout>
The following will display good results on Android 4.3 and 4.4, but strange result on Android 4.2, 4.1, 4.0.3.
On Android 4.2 (bad result)
on Android 4.3 (good result)
Anyone knows why this happens prior to Android 4.3 and how to fix it ?
Thanks !
Seems like I couldn't reproduce the problem since I didn't enable "use GPU host".
Anyway, here's a way to overcome this, even if this feature its enabled :
set android:layerType="software" for the imageView .
I hope you don't need to animate, since this attribute affects the performance.
In order to make it work better (at least for newer Android versions), I suggest making a resource that will be "software" for up to the problematic version (including), and "hardware" from above it.
I've tried other methods of handling it, but they don't work well.
You might be able to reset the layerType at runtime, so you'll get it working well after all.
For me it worked.
just call:
#Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.imageView1).setLayerType(View.LAYER_TYPE_HARDWARE,null);
}

Is there any way to detect if the clock is round?

Might be I missed something but is there any flag for knowing if the clock is round or square?
I could imagine that this is important if you want to design the background of the notifications.
Update for API 23:
To determine if the screen is round you can use
context.getResources().getConfiguration().isScreenRound()
Android reference
Or you can use the round and notround resource qualifiers and let the system apply the proper resources but beware that this will not work on devices running API 22 or lower
Source
Thanks to people who pointed out this change.
Old asnwer
From google I/O talk (https://www.youtube.com/watch?v=naf_WbtFAlY#t=284):
From SDK 20 android.view.View class has
public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener)
and OnApplyWindowInsetsListener has a callback method onApplyWindowsInset
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets){
if (windowInsets.isRound()){
//Do stuff
}
}
You will probably want to use the WatchViewStub, which is included in the wearable-support library. In the stub, you specify a roundLayout and rectLayout, and the correct one will automatically be inflated based on the user's screen shape. See the WatchViewStub sample app that is included in the SDK for an example of how to do this.
EDIT:
The source code for the wearable samples is now online. For this case, take a look at the WatchViewStub sample, which "demonstrates how to specify different layouts for round and rectangular screens": https://developer.android.com/samples/WatchViewStub/project.html
Quick reference:
In the layout:
<android.blah.WatchViewStub
android:layout_width="match_parent"
android:layout_height="match_parent"
app:rectLayout="#layout/rect"
app:roundLayout="#layout/round" />
where rect and round are different layouts for rectangular and round displays.
In the Activity:
setContentView(R.layout.main);
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
#Override
public void onLayoutInflated(WatchViewStub stub) {
mTextView = (TextView) stub.findViewById(R.id.text);
Log.d(TAG, "TextView: " + mTextView.getText() + " view=" + mTextView);
}
});
The onLayoutInflated is optional, but it lets you see what is in the layout that got inflated, so you could do addtional customizations based on which layout the WatchViewStub chose to inflate (rectangular or round).
Starting with API 23 you can use the -round and -notround resource qualifiers. So there is no need in some weeks to use the WatchViewStub.
Just as a small example take this layouts:
layout-round/example.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="#string/round_string"/>
layout-notround/example.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="#string/square_string"/>
Of cause you could also use just one string:
layout/example.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="#string/string"/>
values-round/strings.xml:
<resources>
<string name="string">I am round</string>
</resources>
values-notround/strings.xml:
<resources>
<string name="string">I am square</string>
</resources>
source
Following IonSpin's answer, the following lines work just fine:
if (getResources().getConfiguration().isScreenRound()) {
//code for round wearables
} else {
//code for notround wearables
}
The windowinsets approach failed in my devices, so I did a small trick, ugly but functional.
If you need to check inside your activity then add in your layout a hidden textview with the value "1" in the round layout and "0" in the rect layout.
<TextView
android:id="#+id/isRound"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:text="1" />
Then in the activity:
TextView isRoundText = (TextView) view.findViewById(R.id.isRound);
boolean isRound = "1".equals(isRoundText.getText());
I'd like to add my own two cents here because I think I found a solution, although a bit dummy, rather simple and straightforward.
Why ?
First, the two solutions exposed by #IonSpin are perfectly working, but the first require SDK 23 minimum, and the other is asynchronous...
Using the -round and -notround qualifiers, simply add a dummy empty view in your Activity XML Layout that is inside the layout-round folder as followed :
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:id="#+id/isRound"/>
Then in your Activity onCreate(), simple do:
Log.d(TAG, "is not round ? " + (findViewById(R.id.isRound) == null));
And it should print on a square smartwatch:
MainActivity: is not round ? true
As a new developer on Android Wear, I find this solution a bit unbelievable but it does work with my Sony SmartWatch 3 and on a Virtual Round Android Wear device.
The only shortcoming / trade-off here is that you have to place a dummy view in all your layouts...
Can you guys confirm it works for you as well ?
If I understood correctly it'll be using standard Android resources, meaning you can just put your layout in layout-circle and you're done.

Unwanted space between two ImageView on android

Im using this Layout to put two ImageViews one next to the other, but the two images seems to be separated by 1 transparent pixel space.
The blue background is there to make easier to observe the problem...
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#0000FF">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="5dip">
<ImageView
android:src="#drawable/i_position_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:src="#drawable/i_position_seekbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
The .java is:
public class MainActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
}
}
Im using a device with android 2.2.
I wasnt able to reproduce the glitch on a 2.1-update1 emulator neither on a 1.6 emulator...
Ive checked the images and they have no extra pixels arround them.
Also i tried adding a red 1px width border on the images separately and the glitch is still there, so the images dont seem to be the problem.
These are the problematic images (correctly shown here):
http://dl.dropbox.com/u/7024937/i_position_icon.png
http://dl.dropbox.com/u/7024937/i_position_seekbar.png
And this is what i see in my device:
Thanks.
Sounds strange because I use the same technique in my project and everything seems to be OK. Do you put your drawables into the correct drawable folder. I mean that you should put your images in drawable-hdpi folder if your device has hdpi screen. Sorry, but it's the only thought that came into my mind.
strange, what version SDK are you targeting? i copied your layout and code and made a new project with api level 3 (1.5) and tested it on a 1.5 and 2.2 emulator. On both it worked fine without any spacing.

Categories

Resources