Presentation is loading. Please wait.

Presentation is loading. Please wait.

Android 2: Supporting Different Devices

Similar presentations


Presentation on theme: "Android 2: Supporting Different Devices"— Presentation transcript:

1 Android 2: Supporting Different Devices
Kirk Scott

2

3 Introduction Android devices come in many shapes and sizes all around the world. With a wide range of device types, you have an opportunity to reach a huge audience with your app.

4 In order to be as successful as possible on Android, your app needs to adapt to various device configurations. Some of the important variations that you should consider include different languages, screen sizes, and versions of the Android platform.

5 This class teaches you how to use basic platform features that leverage alternative resources and other features so your app can provide an optimized user experience on a variety of Android-compatible devices, using a single application package (APK).

6 Outline 2.1 Supporting Different Languages and Cultures
2.2 Supporting Different Screens 2.3 Supporting Different Platform Versions

7 2.1 Supporting Different Languages and Cultures
Apps include resources that can be specific to a particular culture. For example, an app can include culture-specific strings that are translated to the language of the current locale.

8 It's a good practice to keep culture-specific resources separated from the rest of your app.
Android resolves language- and culture-specific resources based on the system locale setting. You can provide support for different locales by using the resources directory in your Android project.

9 You can specify resources tailored to the culture of the people who use your app.
You can provide any resource type that is appropriate for the language and culture of your users. For example, the following screenshot shows an app displaying string and drawable resources in the device's default (en_US) locale and the Spanish (es_ES) locale.

10 Figure 1. App using different resources depending on the current locale

11 If you created your project using the Android SDK Tools (read Creating an Android Project), the tools create a res/ directory in the top level of the project. Within this res/ directory are subdirectories for various resource types. There are also a few default files such as res/values/strings.xml, which holds your string values.

12 Supporting different languages goes beyond using locale-specific resources.
Some users choose a language that uses right-to-left (RTL) scripts, such as Arabic or Hebrew, for their UI locale. Other users view or generate content in a language that uses RTL scripts, even though they've set a language that uses LTR scripts, such as English, as their UI locale.

13 To support both types of users, your app needs to do the following:
Employ an RTL UI layout for RTL locales. Detect and declare the direction of text data that's displayed inside formatted messages. Usually, you can just call a method that determines the direction of text data for you.

14 Create Locale Directories and Resource Files
To add support for more locales, create additional directories inside res/. Each directory's name should adhere to the following format: <resource type>-b+<language code>[+<country code>]

15 For example, values-b+es/ contains string resources for locales with the language code es.
Similarly, mipmap-b+es+ES/ contains icons for locales with the es language code and the ES country code. Android loads the appropriate resources according to the locale settings of the device at runtime. For more information, see Providing Alternative Resources.

16 After you’ve decided on the locales to support, create the resource subdirectories and files. For example: MyProject/ res/ values/ strings.xml values-b+es/ mipmap/ country_flag.png mipmap-b+es+ES/

17 English strings (default locale), /values/strings.xml:
For example, the following are some different resource files for different languages: English strings (default locale), /values/strings.xml: <resources> <string name="hello_world">Hello World!</string> </resources>

18 Spanish strings (es locale), /values-es/strings.xml:
<resources> <string name="hello_world">¡Hola Mundo!</string> </resources>

19 United States' flag icon (default locale), /mipmap/country_flag.png:
Figure 2. Icon used for the default (en_US) locale

20 Spain's flag icon (es_ES locale), /mipmap-b+es+ES/country_flag.png:
Figure 3. Icon used for the es_ES locale

21 Note: You can use the locale qualifier (or any configuration qualifier) on any resource type, such as if you want to provide localized versions of your bitmap drawable. For more information, see Localization.

22 Use the Resources in your App
You can reference the resources in your source code and other XML files using each resource's name attribute. In your source code, you can refer to a resource using the syntax R.<resource type>.<resource name>. There are a variety of methods that accept a resource this way.

23 For example: // Get a string resource from your app's Resources
String hello = getResources().getString(R.string.hello_world); // Or supply a string resource to a method that requires a string TextView textView = new TextView(this); textView.setText(R.string.hello_world);

24 In other XML files, you can refer to a resource with the type>/<resource name> whenever the XML attribute accepts a compatible value. For example: <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" />

25 Format Text in Messages
One of the most common tasks in an app is formatting text. Localized messages get formatted by inserting text and numeric data into the appropriate positions. Unfortunately, when dealing with an RTL UI or RTL data, simple formatting can display incorrect or even unreadable text output.

26 Languages such as Arabic, Hebrew, Persian, and Urdu are written in an RTL direction overall.
Some of their elements, however, such as numbers and embedded LTR text, are written in the LTR direction within the otherwise RTL text. Languages that use LTR scripts, including English, are also bidirectional because they can contain embedded RTL scripts that need to be displayed in an RTL direction.

27 Most of the time, it's the apps themselves that generate such instances of embedded opposite-direction text. They insert text data of an arbitrary language—and an arbitrary text direction—into localized messages. This mixing of directions often doesn't include a clear indication of where opposite-direction text starts and ends. These characteristics of app-generated text cause most of the problems.

28 Although the system's default handling of bidirectional text usually renders text as expected, it's possible that text won't render properly when your app inserts it into a localized message. The following situations present examples of cases where it's more likely that text won't appear correctly:

29 Inserted at the very start of the message:
PERSON_NAME is calling you Starts with a number, such as in addresses or telephone numbers:

30 Starts with punctuation, such as in a phone number:
Ends with punctuation: Are you sure? Contains both directions already: The word בננה is Hebrew for banana.

31 Example For example, assume that an app sometimes needs to display the message "Did you mean %s?", with an address inserted in place of the %s at runtime. Because the app supports different UI locales, the message comes from a locale-specific resource and uses the RTL direction when an RTL locale is in use. For a Hebrew UI, it should appear as follows: האם התכוונת ל ?%s

32 The suggestion, however, might come from a database that doesn't include text in the locale's language. For example, if the address in question is for a place in California, it appears in the database using English text.

33 If you insert the address "15 Bay Street, Laurel, CA" into the RTL message without providing any hints regarding text direction, the result isn't expected or correct: ? האם התכוונת ל Bay Street, Laurel, CA 15

34 Note that the house number appears to the right of the address, not to the left as intended, and makes the house number look more like a strange postal code. The same problem may occur if you include RTL text within a message that uses the LTR text direction.

35 Explanation and solution
The problem in previous example occurs because the text formatter doesn't specify that "15" is part of the address, so the system cannot determine whether the "15" is part of the RTL text that comes before it or the LTR text that comes after it.

36 To solve this problem, use the unicodeWrap() method, found in the BidiFormatter class, on every piece of text that you insert into a localized message.

37 The only times when you shouldn't use unicodeWrap() include the following:
The text is being inserted into a machine-readable string, such as a URI or a SQL query. You already know that the piece of text is properly wrapped.

38 The unicodeWrap() method detects the direction of a string and wraps it in Unicode formatting characters that declare that direction. Because the "15" now appears inside text that is declared as LTR, it's displayed in the correct position: ?15 Bay Street, Laurel, CA האם התכוונת ל

39 The following code snippet demonstrates how to use unicodeWrap():
String mySuggestion = "15 Bay Street, Laurel, CA"; BidiFormatter myBidiFormatter = BidiFormatter.getInstance(); // The "did_you_mean" localized string resource includes // a "%s" placeholder for the suggestion. String.format(R.string.did_you_mean, myBidiFormatter.unicodeWrap(mySuggestion));

40 Note: If your app targets Android 4
Note: If your app targets Android 4.3 (API level 18) or higher, use the version of BidiFormatter found in the Android Framework. Otherwise, use the version of BidiFormatter found in the Support Library.

41 Format Numbers Use format strings, not method calls, to convert numbers to strings in your app's logic: String myIntAsString = String.format("%d", myInt); This will format the numbers appropriately for your locale, which may include using a different set of digits.

42 When you use String.format() to create a SQL query on a device whose locale uses its own set of digits, such as Persian and most Arabic locales, problems occur if any of the parameters to the query are numbers. This is because the number is formatted in the locale's digits, and these digits are invalid in SQL.

43 To preserve ASCII-formatted numbers and keep the SQL query valid, you should instead use the overloaded version of String.format() that includes a locale as the first parameter. The locale argument should be Locale.US.

44 Support Layout Mirroring
People who use RTL scripts prefer an RTL user interface, which includes right-aligned menus, right-aligned text, and forward arrows pointing to the left. Figure 4 shows the contrast between the LTR version of a screen within the Settings app and its RTL counterpart:

45 Figure 4. LTR and RTL variants of a screen

46 When adding RTL support to your app, it's particularly important to keep the following points in mind: RTL text mirroring is only supported in apps when used on devices running Android 4.2 (API level 17) or higher. To learn how to support text mirroring on older devices, see Provide support for legacy apps.

47 Note: To view additional design guidelines related to layout mirroring, including a list of elements that you should and shouldn't mirror, see the Bidirectionality material design guidelines. To mirror the UI layout in your app so that it appears RTL in an RTL locale, complete the steps in the following sections.

48 Modify the build and manifest files
Modify your app module's build.gradle file and app manifest file as follows: build.gradle (Module: app) android { ... defaultConfig { targetSdkVersion 17 // Or higher }

49 AndroidManifest.xml <manifest ... > ... <application ... android:supportsRtl="true"> </application> </manifest>

50 Note: If your app targets Android 4. 1
Note: If your app targets Android (API level 16) or lower, the android:supportsRtl attribute is ignored, along with any start and end attribute values that appear in your app's layout files. In this case, RTL layout mirroring doesn't happen automatically in your app.

51 Update existing resources
Convert left and right to start and end, respectively, in each of your existing layout resource files. By doing this, you allow the framework to align your app's UI elements based on the user's language settings. Note: Before updating your resources, learn how to provide support for legacy apps, or apps that target Android (API level 16) and lower.

52 To use the framework's RTL alignment capabilities, change the attributes in your layout files that appear in Table 1. Table 1. Attributes to use when your app supports multiple text directions

53 Attribute supporting LTR only
Attribute supporting LTR and RTL android:gravity="left" android:gravity="start" android:gravity="right" android:gravity="end" android:layout_gravity="left" android:layout_gravity="start" android:layout_gravity="right" android:layout_gravity="end" android:paddingLeft android:paddingStart android:paddingRight android:paddingEnd android:drawableLeft android:drawableStart android:drawableRight android:drawableEnd android:layout_alignLeft android:layout_alignStart android:layout_alignRight android:layout_alignEnd android:layout_marginLeft android:layout_marginStart android:layout_marginRight android:layout_marginEnd android:layout_alignParentLeft android:layout_alignParentStart android:layout_alignParentRight android:layout_alignParentEnd android:layout_toLeftOf android:layout_toStartOf android:layout_toRightOf android:layout_toEndOf

54 Table 2 shows how the system handles UI alignment attributes based on the target SDK version, whether left and right attributes are defined, and whether start and end attributes are defined. Table 2. UI element alignment behavior based on the target SDK version and defined attributes

55 Targeting Android 4.2 (API level 17) or higher?
Left and right defined? Start and end defined? Result Yes start and end resolved, and override left and right No Only left and right are used Only start and end are used left and right are used (start and end are ignored) start and end resolved to left and right

56 Add direction- and language-specific resources
This step involves adding specific versions of your layout, drawables, and values resource files that contain customized values for different languages and text directions.

57 In Android 4.2 (API level 17) and higher, you can use the -ldrtl (layout-direction-right-to-left) and -ldltr (layout-direction-left-to-right) resource qualifiers. To maintain backward compatibility with loading existing resources, older versions of Android use a resource's language qualifiers to infer the correct text direction.

58 Suppose that you want to add a specific layout file to support RTL scripts, such as the Hebrew, Arabic, and Persian languages. To do this, you add a layout-ldrtl/ directory in your res/ directory, as shown in the following example: res/ layout/ main.xml This layout file is loaded by default. layout-ldrtl/ This layout file is loaded for languages using an RTL text direction, including Arabic, Persian, and Hebrew.

59 If you want to add a specific version of the layout that is designed for only Arabic text, your directory structure becomes the following: res/ layout/ main.xml This layout file is loaded by default. layout-ar/ This layout file is loaded for Arabic text. layout-ldrtl/ This layout file is loaded only for non-Arabic languages that use an RTL text direction.

60 Note: Language-specific resources take precedence over layout-direction-specific resources, which take precedence over the default resources.

61 Use supported widgets As of Android 4.2 (API level 17), most framework UI elements support the RTL text direction automatically. However, several framework elements, such as ViewPager, don't support the RTL text direction.

62 Home-screen widgets support the RTL text direction as long as their corresponding manifest files include the attribute assignment android:supportsRtl="true".

63 Provide support for legacy apps
If your app targets Android (API level 16) or lower, also include left and right attributes, in addition to start and end. To check whether your layout should use the RTL text direction, use the following logic: private boolean shouldUseLayoutRtl() { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { return View.LAYOUT_DIRECTION_RTL == getLayoutDirection(); } else { return false; }

64 Note: To avoid compatibility issues, use version 23
Note: To avoid compatibility issues, use version or higher of the Android SDK Build Tools.

65 Test using developer options
On devices running Android 4.4 (API level 19) or higher, you can enable Force RTL layout direction in the on-device developer options. This setting allows you to see text that uses LTR scripts, such as English text, in RTL mode.

66 Update app logic This section describes specific places in your app's logic that you should update when adapting your app for handling multiple text directions.

67 Property changes To handle a change in any RTL-related property—such as layout direction, layout parameters, padding, text direction, text alignment, or drawable positioning—you can use the onRtlPropertiesChanged() callback. This callback allows you to get the current layout direction and update an activity's View objects accordingly.

68 Views If you are creating a UI widget that is not directly part of an activity's view hierarchy, such as a dialog or a toast-like UI element, set the correct layout direction depending on the context. The following code snippet demonstrates how to complete this process: final Configuration config = getContext().getResources().getConfiguration(); view.setLayoutDirection(config.getLayoutDirection());

69 Several methods of the View class require additional consideration:
onMeasure() View measurements might vary depending on text direction. onLayout() If you create your own layout implementation, then you'll need to call super() in your version of onLayout() and adapt your custom logic to support RTL scripts.

70 onDraw() If you're implementing a custom view or adding advanced functionality to a drawing, you'll need to update your code to support RTL scripts. Use the following code to determine whether your widget is in RTL mode: // On devices running Android (API level 16) and lower, // you can call the isLayoutRtl() system method directly. public boolean isLayoutRtl() { return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); }

71 Drawables If you have a drawable that needs to be mirrored for an RTL layout, complete one of these steps based on the version of Android running on the device:

72 On devices running Android 4
On devices running Android 4.3 (API level 18) and lower, you need to add and define the -ldrtl resource files. On Android 4.4 (API level 19) and higher, you can use android:autoMirrored="true" when defining your drawable, which allows the system to handle RTL layout mirroring for you.

73 Note: The android:autoMirrored attribute only works for simple drawables whose bidirectional mirroring is simply a graphical mirroring of the entire drawable.

74 If your drawable contains multiple elements, or if reflecting your drawable would change its interpretation, you should perform the mirroring yourself. Whenever possible, check with a bidirectional expert to determine whether your mirrored drawables make sense to users.

75 Gravity If your app's code is using Gravity.LEFT or Gravity.RIGHT, you will need to change these values to Gravity.START and Gravity.END, respectively. For example, if you're using the following code: switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: // Handle objects that are left-aligned. break; case Gravity.RIGHT: // Handle objects that are right-aligned. }

76 ...you need to change it to the following:
final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection); switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: // Handle objects that are left-aligned. break; case Gravity.RIGHT: // Handle objects that are right-aligned. }

77 This means that you can keep your existing code that handles left-aligned and right-aligned values, even if you are using start and end for your gravity values. Note: When applying your gravity settings, use an overloaded version of Gravity.apply() that includes a layoutDirection argument.

78 Margin and padding To support RTL scripts in your app, follow these best practices related to margin and padding values:

79 Use getMarginStart() and getMarginEnd() instead of the direction-specific attribute equivalents, leftMargin and rightMargin. When using setMargins(), swap the values of the left and right arguments if your app detects RTL scripts. If your app includes custom padding logic, override setPadding() and setPaddingRelative().

80 2.2 Supporting Different Screens

81 Android categorizes device screens using two general properties: size and density.
You should expect that your app will be installed on devices with screens that range in both size and density.

82 As such, you should include some alternative resources that optimize your app’s appearance for different screen sizes and densities. There are four generalized sizes: small, normal, large, xlarge And four generalized densities: low (ldpi), medium (mdpi), high (hdpi), extra high (xhdpi)

83 To declare different layouts and bitmaps you'd like to use for different screens, you must place these alternative resources in separate directories, similar to how you do for different language strings.

84 Also be aware that the screen’s orientation (landscape or portrait) is considered a variation of screen size, so many apps should revise the layout to optimize the user experience in each orientation.

85 Create Different Layouts
To optimize your user experience on different screen sizes, you should create a unique layout XML file for each screen size you want to support. Each layout should be saved into the appropriate resources directory, named with a -<screen_size> suffix. For example, a unique layout for large screens should be saved under res/layout-large/.

86 Note: Android automatically scales your layout in order to properly fit the screen.
Thus, your layouts for different screen sizes don't need to worry about the absolute size of UI elements but instead focus on the layout structure that affects the user experience (such as the size or position of important views relative to sibling views).

87 For example, this project includes a default layout and an alternative layout for large screens:
MyProject/ res/ layout/ main.xml layout-large/

88 Simply reference the layout file in your app as usual:
The file names must be exactly the same, but their contents are different in order to provide an optimized UI for the corresponding screen size. Simply reference the layout file in your app as usual: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); }

89 The system loads the layout file from the appropriate layout directory based on screen size of the device on which your app is running. More information about how Android selects the appropriate resource is available in the Providing Resources guide.

90 As another example, here's a project with an alternative layout for landscape orientation:
MyProject/ res/ layout/ main.xml layout-land/

91 By default, the layout/main.xml file is used for portrait orientation.
If you want to provide a special layout for landscape, including while on large screens, then you need to use both the large and land qualifier: MyProject/ res/ layout/ # default (portrait) main.xml layout-land/ # landscape layout-large/ # large (portrait) layout-large-land/ # large landscape

92 Note: Android 3.2 and above supports an advanced method of defining screen sizes that allows you to specify resources for screen sizes based on the minimum width and height in terms of density-independent pixels. This lesson does not cover this new technique. For more information, read Designing for Multiple Screens.

93 Create Different Bitmaps
You should always provide bitmap resources that are properly scaled to each of the generalized density buckets: low, medium, high and extra-high density. This helps you achieve good graphical quality and performance on all screen densities.

94 To generate these images, you should start with your raw resource in vector format and generate the images for each density using the following size scale: xhdpi: 2.0 hdpi: 1.5 mdpi: 1.0 (baseline) ldpi: 0.75

95 Then, place the files in the appropriate drawable resource directory:
This means that if you generate a 200x200 image for xhdpi devices, you should generate the same resource in 150x150 for hdpi, 100x100 for mdpi, and 75x75 for ldpi devices. Then, place the files in the appropriate drawable resource directory: MyProject/ res/ drawable-xhdpi/ awesomeimage.png drawable-hdpi/ drawable-mdpi/ drawable-ldpi/

96 Any time you the system selects the appropriate bitmap based on the screen's density. Note: Low-density (ldpi) resources aren’t always necessary. When you provide hdpi assets, the system scales them down by one half to properly fit ldpi screens. For more tips and guidelines about creating icon assets for your app, see the Iconography design guide.

97 2.3 Supporting Different Platform Versions

98 While the latest versions of Android often provide great APIs for your app, you should continue to support older versions of Android until more devices get updated. This lesson shows you how to take advantage of the latest APIs while continuing to support older versions as well.

99 The dashboard for Platform Versions is updated regularly to show the distribution of active devices running each version of Android, based on the number of devices that visit the Google Play Store. Generally, it’s a good practice to support about 90% of the active devices, while targeting your app to the latest version.

100 Tip: In order to provide the best features and functionality across several Android versions, you should use the Android Support Library in your app, which allows you to use several recent platform APIs on older versions.

101 Specify Minimum and Target API Levels
The AndroidManifest.xml file describes details about your app and identifies which versions of Android it supports.

102 Specifically, the minSdkVersion and targetSdkVersion attributes for the <uses-sdk> element identify the lowest API level with which your app is compatible and the highest API level against which you’ve designed and tested your app.

103 For example: <manifest xmlns:android=" ... > <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="15" /> ... </manifest>

104 As new versions of Android are released, some style and behaviors may change.
To allow your app to take advantage of these changes and ensure that your app fits the style of each user's device, you should set the targetSdkVersion value to match the latest Android version available.

105 Check System Version at Runtime
Android provides a unique code for each platform version in the Build constants class. Use these codes within your app to build conditions that ensure the code that depends on higher API levels is executed only when those APIs are available on the system. private void setUpActionBar() { // Make sure we're running on Honeycomb or higher // to use ActionBar APIs if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); }

106 Note: When parsing XML resources, Android ignores XML attributes that aren’t supported by the current device. So you can safely use XML attributes that are only supported by newer versions without worrying about older versions breaking when they encounter that code.

107 For example, if you set the targetSdkVersion="11", your app includes the ActionBar by default on Android 3.0 and higher. To then add menu items to the action bar, you need to set android:showAsAction="ifRoom" in your menu resource XML.

108 It's safe to do this in a cross-version XML file, because the older versions of Android simply ignore the showAsAction attribute (that is, you do not need a separate version in res/menu-v11/).

109 Use Platform Styles and Themes
Android provides user experience themes that give apps the look and feel of the underlying operating system. These themes can be applied to your app within the manifest file. By using these built in styles and themes, your app will naturally follow the latest look and feel of Android with each new release.

110 To make your activity look like a dialog box:
<activity To make your activity have a transparent background: <activity To apply your own custom theme defined in /res/values/styles.xml: <activity

111 To apply a theme to your entire app (all activities), add the android:theme attribute to the <application> element: <application For more about creating and using themes, read the Styles and Themes guide.

112 The End


Download ppt "Android 2: Supporting Different Devices"

Similar presentations


Ads by Google