अपने ऐप्लिकेशन को फ़ोल्ड करें

फ़ोल्ड किए जा सकने वाले बड़े डिसप्ले और फ़ोल्ड किए गए खास स्टेटस की वजह से, नए उपयोगकर्ताओं को फ़ोल्ड किए जा सकने वाले डिवाइसों का इस्तेमाल करना आसान हो जाता है. अपने ऐप्लिकेशन को फ़ोल्ड करने की जानकारी देने के लिए, 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 क्लास शामिल है. यह WindowLayoutInfo अपडेट पाने के लिए, WindowInfoTracker को कोड के फ़ॉर्मैट में बदलता है, ताकि रजिस्टर करने (और रजिस्ट्रेशन रद्द करने) की सुविधा काम कर सके. उदाहरण के लिए:

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 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 windowInfoRepo 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()
                        .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);
}

जब आपको पता चल जाए कि डिवाइस टेबलटॉप मोड में है, तब ऐप्लिकेशन का लेआउट उसी हिसाब से अपडेट करें. मीडिया ऐप्लिकेशन के लिए, आम तौर पर इसका मतलब वीडियो को पेज के ऊपरी हिस्से में रखना होता है और फ़ोन को छुए बिना वीडियो देखने या सुनने का अनुभव देने के लिए, पोज़िशनिंग कंट्रोल और सप्लीमेंटल कॉन्टेंट नीचे दिए गए हैं.

उदाहरण

  • MediaPlayerActivity ऐप्लिकेशन: जानें कि Media3 Exoplayer और 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 की मदद से टेबलटॉप पॉस्चर को लागू करना

कोड लैब