बड़े अनफ़ोल्ड किए गए डिसप्ले और फ़ोल्ड किए गए यूनीक स्टेट की वजह से, फ़ोल्ड किए जा सकने वाले डिवाइसों पर लोगों को नया अनुभव मिलता है. अपने ऐप्लिकेशन को फ़ोल्ड किए जा सकने वाले डिवाइसों के हिसाब से बनाने के लिए, Jetpack WindowManager लाइब्रेरी का इस्तेमाल करें. यह लाइब्रेरी, फ़ोल्ड किए जा सकने वाले डिवाइसों की विंडो से जुड़ी सुविधाओं के लिए एपीआई उपलब्ध कराती है. जैसे, फ़ोल्ड और हिंज. फ़ोल्ड किए जा सकने वाले डिवाइसों के लिए बनाए गए ऐप्लिकेशन, अपने लेआउट को इस तरह से अडजस्ट कर सकते हैं कि फ़ोल्ड या हिंज वाले हिस्से में ज़रूरी कॉन्टेंट न दिखे. साथ ही, फ़ोल्ड और हिंज को नैचुरल सेपरेटर के तौर पर इस्तेमाल कर सकते हैं.
यह समझने से कि कोई डिवाइस, टेबलटॉप या बुक पोस्चर जैसे कॉन्फ़िगरेशन के साथ काम करता है या नहीं, अलग-अलग लेआउट के साथ काम करने या खास सुविधाएं देने के बारे में फ़ैसले लिए जा सकते हैं.
विंडो की जानकारी
Jetpack WindowManager में मौजूद WindowInfoTracker
इंटरफ़ेस, विंडो के लेआउट की जानकारी दिखाता है. इंटरफ़ेस का windowLayoutInfo()
तरीका, WindowLayoutInfo
डेटा की एक स्ट्रीम दिखाता है. इससे आपके ऐप्लिकेशन को फ़ोल्ड किए जा सकने वाले डिवाइस की फ़ोल्डिंग की स्थिति के बारे में पता चलता है. WindowInfoTracker#getOrCreate()
तरीका, WindowInfoTracker
का इंस्टेंस बनाता है.
WindowManager, Kotlin फ़्लो और Java कॉलबैक का इस्तेमाल करके WindowLayoutInfo
डेटा इकट्ठा करने की सुविधा देता है.
Kotlin फ़्लो
WindowLayoutInfo
का डेटा कलेक्शन शुरू और बंद करने के लिए, लाइफ़साइकल के बारे में जानने वाली ऐसी को-रूटीन का इस्तेमाल किया जा सकता है जिसे फिर से शुरू किया जा सकता है. इसमें repeatOnLifecycle
कोड ब्लॉक तब एक्ज़ीक्यूट होता है, जब लाइफ़साइकल कम से कम STARTED
पर होता है. साथ ही, यह तब बंद हो जाता है, जब लाइफ़साइकल STOPPED
पर होता है. लाइफ़साइकल के STARTED
होने पर, कोड ब्लॉक अपने-आप फिर से शुरू हो जाता है. यहां दिए गए उदाहरण में, कोड ब्लॉक WindowLayoutInfo
डेटा इकट्ठा करता है और उसका इस्तेमाल करता है:
class DisplayFeaturesActivity : AppCompatActivity() {
private lateinit var binding: ActivityDisplayFeaturesBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDisplayFeaturesBinding.inflate(layoutInflater)
setContentView(binding.root)
lifecycleScope.launch(Dispatchers.Main) {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
WindowInfoTracker.getOrCreate(this@DisplayFeaturesActivity)
.windowLayoutInfo(this@DisplayFeaturesActivity)
.collect { newLayoutInfo ->
// Use newLayoutInfo to update the layout.
}
}
}
}
}
Java कॉलबैक
androidx.window:window-java
डिपेंडेंसी में शामिल कॉलबैक कंपैटिबिलिटी लेयर की मदद से, Kotlin फ़्लो का इस्तेमाल किए बिना WindowLayoutInfo
अपडेट इकट्ठा किए जा सकते हैं. आर्टफ़ैक्ट में WindowInfoTrackerCallbackAdapter
क्लास शामिल है. यह WindowInfoTracker
को इस तरह से अडैप्ट करता है कि WindowLayoutInfo
अपडेट पाने के लिए, कॉलबैक रजिस्टर (और अनरजिस्टर) किए जा सकें. उदाहरण के लिए:
public class SplitLayoutActivity extends AppCompatActivity {
private WindowInfoTrackerCallbackAdapter windowInfoTracker;
private ActivitySplitLayoutBinding binding;
private final LayoutStateChangeCallback layoutStateChangeCallback =
new LayoutStateChangeCallback();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivitySplitLayoutBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
windowInfoTracker =
new WindowInfoTrackerCallbackAdapter(WindowInfoTracker.getOrCreate(this));
}
@Override
protected void onStart() {
super.onStart();
windowInfoTracker.addWindowLayoutInfoListener(
this, Runnable::run, layoutStateChangeCallback);
}
@Override
protected void onStop() {
super.onStop();
windowInfoTracker
.removeWindowLayoutInfoListener(layoutStateChangeCallback);
}
class LayoutStateChangeCallback implements Consumer<WindowLayoutInfo> {
@Override
public void accept(WindowLayoutInfo newLayoutInfo) {
SplitLayoutActivity.this.runOnUiThread( () -> {
// Use newLayoutInfo to update the layout.
});
}
}
}
RxJava की सुविधा
अगर पहले से ही RxJava (वर्शन 2
या 3
) का इस्तेमाल किया जा रहा है, तो ऐसे आर्टफ़ैक्ट का फ़ायदा लिया जा सकता है जिनकी मदद से, Kotlin फ़्लो का इस्तेमाल किए बिना WindowLayoutInfo
अपडेट इकट्ठा किए जा सकते हैं. इसके लिए, Observable
या Flowable
का इस्तेमाल किया जा सकता है.
androidx.window:window-rxjava2
और androidx.window:window-rxjava3
डिपेंडेंसी से मिली कंपैटबिलिटी लेयर में, WindowInfoTracker#windowLayoutInfoFlowable()
और WindowInfoTracker#windowLayoutInfoObservable()
तरीके शामिल होते हैं. इनकी मदद से, आपका ऐप्लिकेशन WindowLayoutInfo
अपडेट पा सकता है. उदाहरण के लिए:
class RxActivity: AppCompatActivity {
private lateinit var binding: ActivityRxBinding
private var disposable: Disposable? = null
private lateinit var observable: Observable<WindowLayoutInfo>
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivitySplitLayoutBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
// Create a new observable.
observable = WindowInfoTracker.getOrCreate(this@RxActivity)
.windowLayoutInfoObservable(this@RxActivity)
}
@Override
protected void onStart() {
super.onStart();
// Subscribe to receive WindowLayoutInfo updates.
disposable?.dispose()
disposable = observable
.observeOn(AndroidSchedulers.mainThread())
.subscribe { newLayoutInfo ->
// Use newLayoutInfo to update the layout.
}
}
@Override
protected void onStop() {
super.onStop();
// Dispose of the WindowLayoutInfo observable.
disposable?.dispose()
}
}
फ़ोल्ड किए जा सकने वाले डिसप्ले की सुविधाएं
Jetpack WindowManager की WindowLayoutInfo
क्लास, डिसप्ले विंडो की सुविधाओं को DisplayFeature
एलिमेंट की सूची के तौर पर उपलब्ध कराती है.
FoldingFeature
, DisplayFeature
का एक टाइप है. यह फ़ोल्ड किए जा सकने वाले डिसप्ले के बारे में जानकारी देता है. इसमें ये प्रॉपर्टी शामिल हैं:
state
: डिवाइस के मुड़े होने की स्थिति,FLAT
याHALF_OPENED
orientation
: फ़ोल्ड या हिंज का ओरिएंटेशन,HORIZONTAL
याVERTICAL
occlusionType
: फ़ोल्ड या हिंज, डिसप्ले के किसी हिस्से को छिपाता है या नहीं,NONE
याFULL
isSeparating
: फ़ोल्ड या हिंज की वजह से, दो लॉजिकल डिसप्ले एरिया बनते हैं या नहीं. इसकी वैल्यू सही या गलत होती है
फ़ोल्ड किए जा सकने वाले डिवाइस में, HALF_OPENED
हमेशा isSeparating
के तौर पर रिपोर्ट करता है, क्योंकि स्क्रीन को दो डिसप्ले एरिया में बांटा जाता है. इसके अलावा, दो स्क्रीन वाले डिवाइस पर isSeparating
हमेशा सही होता है. ऐसा तब होता है, जब ऐप्लिकेशन दोनों स्क्रीन पर दिखता है.
FoldingFeature
bounds
प्रॉपर्टी (DisplayFeature
से इनहेरिट की गई) फ़ोल्डिंग सुविधा के बाउंडिंग रेक्टैंगल को दिखाती है. जैसे, फ़ोल्ड या हिंज.
बाउंड्री का इस्तेमाल करके, स्क्रीन पर एलिमेंट को सुविधा के हिसाब से सेट किया जा सकता है:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) {
// ...
lifecycleScope.launch(Dispatchers.Main) {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
// Safely collects from WindowInfoTracker when the lifecycle is
// STARTED and stops collection when the lifecycle is STOPPED.
WindowInfoTracker.getOrCreate(this@MainActivity)
.windowLayoutInfo(this@MainActivity)
.collect { layoutInfo ->
// New posture information.
val foldingFeature = layoutInfo.displayFeatures
.filterIsInstance<FoldingFeature>()
.firstOrNull()
// Use information from the foldingFeature object.
}
}
}
}
Java
private WindowInfoTrackerCallbackAdapter windowInfoTracker;
private final LayoutStateChangeCallback layoutStateChangeCallback =
new LayoutStateChangeCallback();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// ...
windowInfoTracker =
new WindowInfoTrackerCallbackAdapter(WindowInfoTracker.getOrCreate(this));
}
@Override
protected void onStart() {
super.onStart();
windowInfoTracker.addWindowLayoutInfoListener(
this, Runnable::run, layoutStateChangeCallback);
}
@Override
protected void onStop() {
super.onStop();
windowInfoTracker.removeWindowLayoutInfoListener(layoutStateChangeCallback);
}
class LayoutStateChangeCallback implements Consumer<WindowLayoutInfo> {
@Override
public void accept(WindowLayoutInfo newLayoutInfo) {
// Use newLayoutInfo to update the Layout.
List<DisplayFeature> displayFeatures = newLayoutInfo.getDisplayFeatures();
for (DisplayFeature feature : displayFeatures) {
if (feature instanceof FoldingFeature) {
// Use information from the feature object.
}
}
}
}
टेबलटॉप पॉस्चर
FoldingFeature
ऑब्जेक्ट में शामिल जानकारी का इस्तेमाल करके, आपका ऐप्लिकेशन टेबलटॉप जैसे पोस्चर के साथ काम कर सकता है. टेबलटॉप पोस्चर में, फ़ोन को किसी सतह पर रखा जाता है, हिंज हॉरिज़ॉन्टल स्थिति में होता है, और फ़ोल्ड की जा सकने वाली स्क्रीन आधी खुली होती है.
टेबलटॉप मोड में फ़ोन को बिना हाथ में लिए इस्तेमाल किया जा सकता है. टेबलटॉप मोड में डिवाइस को रखकर मीडिया देखा जा सकता है, फ़ोटो खींची जा सकती हैं, और वीडियो कॉल किए जा सकते हैं.

यह पता लगाने के लिए कि डिवाइस टेबलटॉप मोड में है या नहीं, FoldingFeature.State
और FoldingFeature.Orientation
का इस्तेमाल करें:
Kotlin
fun isTableTopPosture(foldFeature : FoldingFeature?) : Boolean {
contract { returns(true) implies (foldFeature != null) }
return foldFeature?.state == FoldingFeature.State.HALF_OPENED &&
foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL
}
Java
boolean isTableTopPosture(FoldingFeature foldFeature) {
return (foldFeature != null) &&
(foldFeature.getState() == FoldingFeature.State.HALF_OPENED) &&
(foldFeature.getOrientation() == FoldingFeature.Orientation.HORIZONTAL);
}
जब आपको पता चल जाए कि डिवाइस को टेबलटॉप मोड में रखा गया है, तब अपने ऐप्लिकेशन के लेआउट को उसके हिसाब से अपडेट करें. मीडिया ऐप्लिकेशन के लिए, इसका मतलब आम तौर पर यह होता है कि फ़ोल्ड के ऊपर वीडियो चलाने की सुविधा दी जाए. साथ ही, बिना हाथ लगाए वीडियो देखने या संगीत सुनने के लिए, कंट्रोल और अन्य कॉन्टेंट को फ़ोल्ड के ठीक नीचे रखा जाए.
Android 15 (एपीआई लेवल 35) और इसके बाद के वर्शन पर, सिंक्रोनस एपीआई को कॉल किया जा सकता है. इससे यह पता लगाया जा सकता है कि डिवाइस, टेबलटॉप मोड के साथ काम करता है या नहीं. भले ही, डिवाइस की मौजूदा स्थिति कुछ भी हो.
यह एपीआई, डिवाइस के साथ काम करने वाले पोस्चर की सूची उपलब्ध कराता है. अगर सूची में टेबलटॉप मोड शामिल है, तो इस मोड के साथ काम करने के लिए अपने ऐप्लिकेशन के लेआउट को दो हिस्सों में बांटा जा सकता है. साथ ही, टेबलटॉप और फ़ुल‑स्क्रीन लेआउट के लिए, अपने ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) पर A/B टेस्ट किए जा सकते हैं.
Kotlin
if (WindowSdkExtensions.getInstance().extensionsVersion >= 6) {
val postures = WindowInfoTracker.getOrCreate(context).supportedPostures
if (postures.contains(TABLE_TOP)) {
// Device supports tabletop posture.
}
}
Java
if (WindowSdkExtensions.getInstance().getExtensionVersion() >= 6) {
List<SupportedPosture> postures = WindowInfoTracker.getOrCreate(context).getSupportedPostures();
if (postures.contains(SupportedPosture.TABLETOP)) {
// Device supports tabletop posture.
}
}
उदाहरण
MediaPlayerActivity
ऐप्लिकेशन: फ़ोल्ड किए जा सकने वाले डिवाइसों के लिए वीडियो प्लेयर बनाने के लिए, Media3 Exoplayer और WindowManager का इस्तेमाल करने का तरीका जानें.Jetpack WindowManager की मदद से, फ़ोल्ड किए जा सकने वाले डिवाइसों पर अपने कैमरा ऐप्लिकेशन को ऑप्टिमाइज़ करें कोडलैब: फ़ोटोग्राफ़ी ऐप्लिकेशन के लिए, टेबलटॉप मोड को लागू करने का तरीका जानें. स्क्रीन के ऊपर के आधे हिस्से (फ़ोल्ड के ऊपर) पर व्यूफ़ाइंडर और नीचे के आधे हिस्से (फ़ोल्ड के नीचे) पर कंट्रोल दिखाएं.
किताब पढ़ने की मुद्रा
फ़ोल्ड किए जा सकने वाले डिवाइस की एक और खास सुविधा है, बुक पोस्चर. इसमें डिवाइस को आधा खोला जाता है और हिंज वर्टिकल होता है. किताब की तरह डिवाइस को पकड़ने की मुद्रा, ई-बुक पढ़ने के लिए सबसे सही है. बड़ी स्क्रीन वाले फ़ोल्ड किए जा सकने वाले डिवाइस पर, किताब को दो पेज वाले लेआउट में दिखाया जाता है. इससे किताब पढ़ने का अनुभव मिलता है.
अगर आपको हाथ का इस्तेमाल किए बिना फ़ोटो लेते समय, अलग आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) में फ़ोटो लेनी है, तो इसका इस्तेमाल फ़ोटोग्राफ़ी के लिए भी किया जा सकता है.
किताब की तरह डिवाइस को पकड़ने के लिए, टेबलटॉप मोड में डिवाइस को पकड़ने के लिए इस्तेमाल की जाने वाली तकनीकों का इस्तेमाल करें. इन दोनों कोड में सिर्फ़ यह अंतर है कि कोड को यह जांच करनी चाहिए कि फ़ोल्डिंग की सुविधा का ओरिएंटेशन हॉरिज़ॉन्टल के बजाय वर्टिकल है या नहीं:
Kotlin
fun isBookPosture(foldFeature : FoldingFeature?) : Boolean {
contract { returns(true) implies (foldFeature != null) }
return foldFeature?.state == FoldingFeature.State.HALF_OPENED &&
foldFeature.orientation == FoldingFeature.Orientation.VERTICAL
}
Java
boolean isBookPosture(FoldingFeature foldFeature) {
return (foldFeature != null) &&
(foldFeature.getState() == FoldingFeature.State.HALF_OPENED) &&
(foldFeature.getOrientation() == FoldingFeature.Orientation.VERTICAL);
}
विंडो के साइज़ में बदलाव
डिवाइस के कॉन्फ़िगरेशन में बदलाव होने की वजह से, ऐप्लिकेशन का डिसप्ले एरिया बदल सकता है. उदाहरण के लिए, जब डिवाइस को फ़ोल्ड या अनफ़ोल्ड किया जाता है, घुमाया जाता है या मल्टी‑विंडो मोड में किसी विंडो का साइज़ बदला जाता है.
Jetpack WindowManager WindowMetricsCalculator
क्लास की मदद से, मौजूदा और ज़्यादा से ज़्यादा विंडो मेट्रिक को वापस पाया जा सकता है. एपीआई लेवल 30 में पेश किए गए प्लैटफ़ॉर्म WindowMetrics
की तरह ही, WindowManager WindowMetrics
विंडो की सीमाएं तय करता है. हालांकि, यह एपीआई, एपीआई लेवल 14 तक के वर्शन के साथ काम करता है.
विंडो के साइज़ के क्लास का इस्तेमाल करना लेख पढ़ें.
अन्य संसाधन
सैंपल
- Jetpack WindowManager: Jetpack WindowManager लाइब्रेरी इस्तेमाल करने का उदाहरण
- Jetcaster : Compose की मदद से टेबलटॉप मोड लागू करना
कोडलैब
- Jetpack WindowManager की मदद से, फ़ोल्ड किए जा सकने वाले और Dual Screen वाले डिवाइस बनाना
- Jetpack WindowManager की मदद से, फ़ोल्ड किए जा सकने वाले डिवाइसों पर कैमरा ऐप्लिकेशन को ऑप्टिमाइज़ करना