অ্যাক্টিভিটি এম্বেডিং একটি অ্যাপ্লিকেশনের টাস্ক উইন্ডোকে দুটি অ্যাক্টিভিটি বা একই অ্যাক্টিভিটির দুটি ইনস্ট্যান্সের মধ্যে বিভক্ত করে বড় স্ক্রিনের ডিভাইসে অ্যাপগুলিকে অপ্টিমাইজ করে।

যদি আপনার অ্যাপে একাধিক অ্যাক্টিভিটি থাকে, তাহলে অ্যাক্টিভিটি এম্বেডিং আপনাকে ট্যাবলেট, ফোল্ডেবল এবং ChromeOS ডিভাইসে উন্নত ব্যবহারকারীর অভিজ্ঞতা প্রদান করতে সক্ষম করে।
অ্যাক্টিভিটি এম্বেডিংয়ের জন্য কোনও কোড রিফ্যাক্টরিং প্রয়োজন হয় না। আপনি একটি XML কনফিগারেশন ফাইল তৈরি করে অথবা Jetpack WindowManager API কল করে আপনার অ্যাপের কার্যকলাপগুলি কীভাবে প্রদর্শন করে তা নির্ধারণ করতে পারেন—পাশাপাশি অথবা স্ট্যাক করা—।
ছোট স্ক্রিনের জন্য সমর্থন স্বয়ংক্রিয়ভাবে বজায় থাকে। যখন আপনার অ্যাপটি ছোট স্ক্রিনযুক্ত ডিভাইসে থাকে, তখন কার্যকলাপগুলি একটির উপরে আরেকটি স্ট্যাক করা হয়। বড় স্ক্রিনে, কার্যকলাপগুলি পাশাপাশি প্রদর্শিত হয়। সিস্টেমটি আপনার তৈরি কনফিগারেশনের উপর ভিত্তি করে উপস্থাপনা নির্ধারণ করে - কোনও ব্রাঞ্চিং লজিকের প্রয়োজন হয় না।
অ্যাক্টিভিটি এম্বেডিং ডিভাইসের ওরিয়েন্টেশন পরিবর্তনগুলিকে সামঞ্জস্য করে এবং ভাঁজযোগ্য ডিভাইসগুলিতে নির্বিঘ্নে কাজ করে, ডিভাইসটি ভাঁজ এবং উন্মোচিত হওয়ার সাথে সাথে স্ট্যাকিং এবং আনস্ট্যাকিং কার্যক্রম।
অ্যান্ড্রয়েড ১২এল (এপিআই লেভেল ৩২) এবং তার উচ্চতর ভার্সনে চলমান বেশিরভাগ বড় স্ক্রিনের ডিভাইসে অ্যাক্টিভিটি এম্বেডিং সমর্থিত।
টাস্ক উইন্ডো বিভক্ত করুন
অ্যাক্টিভিটি এম্বেডিং অ্যাপ টাস্ক উইন্ডোটিকে দুটি কন্টেইনারে বিভক্ত করে: প্রাথমিক এবং মাধ্যমিক। কন্টেইনারগুলি মূল কার্যকলাপ থেকে শুরু হওয়া কার্যকলাপ বা কন্টেইনারে ইতিমধ্যেই থাকা অন্যান্য কার্যকলাপ থেকে শুরু হওয়া কার্যকলাপগুলিকে ধারণ করে।
অ্যাক্টিভিটিগুলি চালু হওয়ার সাথে সাথে সেকেন্ডারি কন্টেইনারে স্ট্যাক করা হয় এবং সেকেন্ডারি কন্টেইনারটি ছোট স্ক্রিনে প্রাইমারি কন্টেইনারের উপরে স্ট্যাক করা হয়, তাই অ্যাক্টিভিটি স্ট্যাকিং এবং ব্যাক নেভিগেশন আপনার অ্যাপে ইতিমধ্যেই তৈরি করা অ্যাক্টিভিটির ক্রমের সাথে সামঞ্জস্যপূর্ণ।
অ্যাক্টিভিটি এম্বেডিং আপনাকে বিভিন্ন উপায়ে অ্যাক্টিভিটি প্রদর্শন করতে সক্ষম করে। আপনার অ্যাপটি একই সাথে দুটি অ্যাক্টিভিটি পাশাপাশি বা একটির উপরে চালু করে টাস্ক উইন্ডোটি বিভক্ত করতে পারে:


একটি কার্যকলাপ যা পুরো টাস্ক উইন্ডো দখল করে, তার সাথে একটি নতুন কার্যকলাপ চালু করে একটি বিভক্তি তৈরি করতে পারে:

যেসব কার্যকলাপ ইতিমধ্যেই বিভক্ত এবং একটি টাস্ক উইন্ডো ভাগ করে নেওয়ার ক্ষেত্রে রয়েছে, সেগুলি নিম্নলিখিত উপায়ে অন্যান্য কার্যকলাপ চালু করতে পারে:
অন্য কার্যকলাপের উপরে:

চিত্র ৪। কার্যকলাপ A, কার্যকলাপ B এর পাশ দিয়ে কার্যকলাপ C শুরু করে। পাশে, এবং পূর্ববর্তী প্রাথমিক কার্যকলাপ গোপন করে বিভক্তটিকে পাশে সরান:

চিত্র ৫। কার্যকলাপ B, কার্যকলাপ C কে পাশে শুরু করে এবং বিভক্তিকে পাশে সরিয়ে দেয়। উপরে একটি কার্যকলাপ চালু করুন; অর্থাৎ, একই কার্যকলাপ স্ট্যাকে:

চিত্র ৬। কার্যকলাপ B, কোনও অতিরিক্ত উদ্দেশ্য পতাকা ছাড়াই কার্যকলাপ C শুরু করে। একই কাজে একটি অ্যাক্টিভিটি ফুল উইন্ডো চালু করুন:

চিত্র ৭। অ্যাক্টিভিটি A অথবা অ্যাক্টিভিটি B অ্যাক্টিভিটি C শুরু করে যা টাস্ক উইন্ডোটি পূরণ করে।
পিছনের নেভিগেশন
বিভিন্ন ধরণের অ্যাপ্লিকেশনের বিভিন্ন ধরণের ব্যাক নেভিগেশন নিয়ম থাকতে পারে, যা কার্যকলাপের মধ্যে নির্ভরতা বা ব্যবহারকারীরা কীভাবে ব্যাক ইভেন্টটি ট্রিগার করে তার উপর নির্ভর করে, উদাহরণস্বরূপ:
- একসাথে যাওয়া: যদি কার্যকলাপগুলি সম্পর্কিত হয়, এবং একটি অন্যটি ছাড়া দেখানো উচিত নয়, তাহলে উভয়ই শেষ করার জন্য পিছনের নেভিগেশন কনফিগার করা যেতে পারে।
- একা একা কাজ করা: যদি কার্যকলাপগুলি সম্পূর্ণ স্বাধীন হয়, তাহলে একটি কার্যকলাপের পিছনে নেভিগেশন টাস্ক উইন্ডোতে অন্য কার্যকলাপের অবস্থাকে প্রভাবিত করে না।
বোতাম নেভিগেশন ব্যবহার করার সময় ব্যাক ইভেন্টটি শেষ ফোকাস করা কার্যকলাপে পাঠানো হয়।
অঙ্গভঙ্গি-ভিত্তিক নেভিগেশনের জন্য:
অ্যান্ড্রয়েড ১৪ (এপিআই লেভেল ৩৪) এবং তার নিচের ভার্সন — ব্যাক ইভেন্টটি সেই অ্যাক্টিভিটিতে পাঠানো হয় যেখানে অঙ্গভঙ্গিটি ঘটেছে। যখন ব্যবহারকারীরা স্ক্রিনের বাম দিক থেকে সোয়াইপ করেন, তখন ব্যাক ইভেন্টটি স্প্লিট উইন্ডোর বাম দিকের প্যানে থাকা অ্যাক্টিভিটিতে পাঠানো হয়। যখন ব্যবহারকারীরা স্ক্রিনের ডান দিক থেকে সোয়াইপ করেন, তখন ব্যাক ইভেন্টটি ডান দিকের প্যানে থাকা অ্যাক্টিভিটিতে পাঠানো হয়।
অ্যান্ড্রয়েড ১৫ (এপিআই লেভেল ৩৫) এবং উচ্চতর
একই অ্যাপ থেকে একাধিক কার্যকলাপ পরিচালনা করার সময়, সোয়াইপের দিক নির্বিশেষে অঙ্গভঙ্গি শীর্ষ কার্যকলাপটি সম্পন্ন করে, আরও একীভূত অভিজ্ঞতা প্রদান করে।
ভিন্ন অ্যাপ (ওভারলে) থেকে দুটি কার্যকলাপ জড়িত পরিস্থিতিতে, পিছনের ইভেন্টটি ফোকাসের শেষ কার্যকলাপে পরিচালিত হয়, বোতাম নেভিগেশনের আচরণের সাথে সামঞ্জস্যপূর্ণ।
মাল্টি-পেন লেআউট
জেটপ্যাক উইন্ডো ম্যানেজার আপনাকে অ্যান্ড্রয়েড ১২এল (এপিআই লেভেল ৩২) বা তার বেশি ভার্সনের বড় স্ক্রিনের ডিভাইসে এবং আগের প্ল্যাটফর্ম ভার্সনের কিছু ডিভাইসে মাল্টি-পেন লেআউট এম্বেড করে একটি অ্যাক্টিভিটি তৈরি করতে সক্ষম করে। SlidingPaneLayout মতো খণ্ড বা ভিউ-ভিত্তিক লেআউটের পরিবর্তে একাধিক অ্যাক্টিভিটির উপর ভিত্তি করে বিদ্যমান অ্যাপগুলি সোর্স কোড রিফ্যাক্টরিং ছাড়াই উন্নত বড় স্ক্রিন ব্যবহারকারীর অভিজ্ঞতা প্রদান করতে পারে।
একটি সাধারণ উদাহরণ হল তালিকা-বিস্তারিত বিভাজন। উচ্চমানের উপস্থাপনা নিশ্চিত করার জন্য, সিস্টেমটি তালিকা কার্যকলাপ শুরু করে এবং তারপরে অ্যাপ্লিকেশনটি অবিলম্বে বিস্তারিত কার্যকলাপ শুরু করে। ট্রানজিশন সিস্টেমটি উভয় কার্যকলাপ আঁকা না হওয়া পর্যন্ত অপেক্ষা করে, তারপর সেগুলিকে একসাথে প্রদর্শন করে। ব্যবহারকারীর কাছে, দুটি কার্যকলাপ এক হিসাবে চালু হয়।

বৈশিষ্ট্য বিভক্ত করুন
বিভক্ত কন্টেইনারগুলির মধ্যে টাস্ক উইন্ডোটি কীভাবে সমানুপাতিক এবং কন্টেইনারগুলি একে অপরের সাপেক্ষে কীভাবে সাজানো হয়েছে তা আপনি নির্দিষ্ট করতে পারেন।
একটি XML কনফিগারেশন ফাইলে সংজ্ঞায়িত নিয়মের জন্য, নিম্নলিখিত বৈশিষ্ট্যগুলি সেট করুন:
-
splitRatio: কন্টেইনারের অনুপাত নির্ধারণ করে। মানটি হল খোলা ব্যবধানে (0.0, 1.0) একটি ভাসমান বিন্দু সংখ্যা। -
splitLayoutDirection: স্প্লিট কন্টেইনারগুলিকে একে অপরের সাপেক্ষে কীভাবে সাজানো হবে তা নির্দিষ্ট করে। মানগুলির মধ্যে রয়েছে:-
ltr: বাম থেকে ডানে -
rtl: ডান থেকে বামে -
locale: লোকেল সেটিং থেকেltrঅথবাrtlনির্ধারণ করা হয়
-
উদাহরণের জন্য XML কনফিগারেশন বিভাগটি দেখুন।
WindowManager API ব্যবহার করে তৈরি নিয়মগুলির জন্য, SplitAttributes.Builder দিয়ে একটি SplitAttributes অবজেক্ট তৈরি করুন এবং নিম্নলিখিত বিল্ডার পদ্ধতিগুলি কল করুন:
-
setSplitType(): বিভক্ত কন্টেইনারগুলির অনুপাত সেট করে।SplitAttributes.SplitType.ratio()পদ্ধতি সহ বৈধ আর্গুমেন্টের জন্যSplitAttributes.SplitTypeদেখুন। setLayoutDirection(): কন্টেইনারের লেআউট সেট করে। সম্ভাব্য মানগুলির জন্যSplitAttributes.LayoutDirectionদেখুন।
উদাহরণের জন্য WindowManager API বিভাগটি দেখুন।

বিভক্ত ওরিয়েন্টেশন
ডিসপ্লের মাত্রা এবং আকৃতির অনুপাত অ্যাক্টিভিটি এমবেডিং স্প্লিটগুলিতে অ্যাক্টিভিটির অবস্থান নির্ধারণ করে। বৃহৎ ল্যান্ডস্কেপ ডিসপ্লেতে, অ্যাক্টিভিটিগুলি পাশাপাশি প্রদর্শিত হয়; লম্বা পোর্ট্রেট ডিসপ্লেতে বা ফোল্ডেবলের উপর টেবিলটপ ভঙ্গিতে, একটির উপরে আরেকটি প্রদর্শিত হয়।
আপনি SplitController SplitAttributes ক্যালকুলেটর দিয়ে স্প্লিট ওরিয়েন্টেশন নির্দিষ্ট করতে পারেন। ক্যালকুলেটরটি সক্রিয় SplitRule এর জন্য SplitAttributes গণনা করে।
বিভিন্ন ডিভাইসের অবস্থার জন্য প্যারেন্ট কন্টেইনারটিকে বিভিন্ন দিকে বিভক্ত করতে ক্যালকুলেটর ব্যবহার করুন, উদাহরণস্বরূপ:
কোটলিন
if (WindowSdkExtensions.getInstance().extensionVersion >= 2) { SplitController.getInstance(this).setSplitAttributesCalculator { params -> val parentConfiguration = params.parentConfiguration val builder = SplitAttributes.Builder() return@setSplitAttributesCalculator if (parentConfiguration.screenWidthDp >= 840) { // Side-by-side dual-pane layout for wide displays. builder .setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE) .build() } else if (parentConfiguration.screenHeightDp >= 600) { // Horizontal split for tall displays. builder .setLayoutDirection(SplitAttributes.LayoutDirection.BOTTOM_TO_TOP) .build() } else { // Fallback to expand the secondary container. builder .setSplitType(SPLIT_TYPE_EXPAND) .build() } } }
জাভা
if (WindowSdkExtensions.getInstance().getExtensionVersion() >= 2) { SplitController.getInstance(this).setSplitAttributesCalculator(params -> { Configuration parentConfiguration = params.getParentConfiguration(); SplitAttributes.Builder builder = new SplitAttributes.Builder(); if (parentConfiguration.screenWidthDp >= 840) { // Side-by-side dual-pane layout for wide displays. return builder .setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE) .build(); } else if (parentConfiguration.screenHeightDp >= 600) { // Horizontal split for tall displays. return builder .setLayoutDirection(SplitAttributes.LayoutDirection.BOTTOM_TO_TOP) .build(); } else { // Fallback to expand the secondary container. return builder .setSplitType(SplitType.SPLIT_TYPE_EXPAND) .build(); } }); }
ফোল্ডেবল ডিভাইসে, ডিভাইসটি ল্যান্ডস্কেপ হলে আপনি স্ক্রিনটি উল্লম্বভাবে বিভক্ত করতে পারেন, ডিভাইসটি পোর্ট্রেট হলে একটি একক কার্যকলাপ প্রদর্শন করতে পারেন এবং ডিভাইসটি টেবিলটপ অবস্থানে থাকলে স্ক্রিনটি অনুভূমিকভাবে বিভক্ত করতে পারেন:
কোটলিন
if (WindowSdkExtensions.getInstance().extensionVersion >= 2) { SplitController.getInstance(this).setSplitAttributesCalculator { params -> val tag = params.splitRuleTag val parentWindowMetrics = params.parentWindowMetrics val parentConfiguration = params.parentConfiguration val foldingFeatures = params.parentWindowLayoutInfo.displayFeatures.filterIsInstance<FoldingFeature>() val feature = if (foldingFeatures.size == 1) foldingFeatures[0] else null val builder = SplitAttributes.Builder() builder.setSplitType(SPLIT_TYPE_HINGE) return@setSplitAttributesCalculator if (feature?.isSeparating == true) { // Horizontal split for tabletop posture. builder .setSplitType(SPLIT_TYPE_HINGE) .setLayoutDirection( if (feature.orientation == FoldingFeature.Orientation.HORIZONTAL) { SplitAttributes.LayoutDirection.BOTTOM_TO_TOP } else { SplitAttributes.LayoutDirection.LOCALE } ) .build() } else if (parentConfiguration.screenWidthDp >= 840) { // Side-by-side dual-pane layout for wide displays. builder .setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE) .build() } else { // No split for tall displays. builder .setSplitType(SPLIT_TYPE_EXPAND) .build() } } }
জাভা
if (WindowSdkExtensions.getInstance().getExtensionVersion() >= 2) { SplitController.getInstance(this).setSplitAttributesCalculator(params -> { String tag = params.getSplitRuleTag(); WindowMetrics parentWindowMetrics = params.getParentWindowMetrics(); Configuration parentConfiguration = params.getParentConfiguration(); List<FoldingFeature> foldingFeatures = params.getParentWindowLayoutInfo().getDisplayFeatures().stream().filter( item -> item instanceof FoldingFeature) .map(item -> (FoldingFeature) item) .collect(Collectors.toList()); FoldingFeature feature = foldingFeatures.size() == 1 ? foldingFeatures.get(0) : null; SplitAttributes.Builder builder = new SplitAttributes.Builder(); builder.setSplitType(SplitType.SPLIT_TYPE_HINGE); if (feature != null && feature.isSeparating()) { // Horizontal slit for tabletop posture. return builder .setSplitType(SplitType.SPLIT_TYPE_HINGE) .setLayoutDirection( feature.getOrientation() == FoldingFeature.Orientation.HORIZONTAL ? SplitAttributes.LayoutDirection.BOTTOM_TO_TOP : SplitAttributes.LayoutDirection.LOCALE) .build(); } else if (parentConfiguration.screenWidthDp >= 840) { // Side-by-side dual-pane layout for wide displays. return builder .setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE) .build(); } else { // No split for tall displays. return builder .setSplitType(SplitType.SPLIT_TYPE_EXPAND) .build(); } }); }
স্থানধারক
প্লেসহোল্ডার অ্যাক্টিভিটি হল খালি সেকেন্ডারি অ্যাক্টিভিটি যা অ্যাক্টিভিটি স্প্লিটের একটি অংশ দখল করে। এগুলি শেষ পর্যন্ত এমন অন্য অ্যাক্টিভিটি দিয়ে প্রতিস্থাপন করা হয় যেখানে কন্টেন্ট থাকে। উদাহরণস্বরূপ, একটি প্লেসহোল্ডার অ্যাক্টিভিটি তালিকা-বিস্তারিত লেআউটে অ্যাক্টিভিটি স্প্লিটের সেকেন্ডারি পার্শ্ব দখল করতে পারে যতক্ষণ না তালিকা থেকে একটি আইটেম নির্বাচন করা হয়, সেই সময়ে নির্বাচিত তালিকা আইটেমের বিশদ তথ্য সম্বলিত একটি অ্যাক্টিভিটি প্লেসহোল্ডারকে প্রতিস্থাপন করে।
ডিফল্টরূপে, সিস্টেমটি কেবল তখনই স্থানধারক প্রদর্শন করে যখন কোনও কার্যকলাপ বিভাজনের জন্য পর্যাপ্ত স্থান থাকে। যখন প্রদর্শনের আকার প্রস্থ বা উচ্চতায় পরিবর্তিত হয় যা বিভাজন প্রদর্শনের জন্য খুব ছোট হয় তখন স্থানধারকগুলি স্বয়ংক্রিয়ভাবে শেষ হয়ে যায়। যখন স্থান অনুমতি দেয়, তখন সিস্টেমটি পুনরায় আরম্ভ করা অবস্থায় স্থানধারকটি পুনরায় চালু করে।

তবে, SplitPlaceholderRule এর stickyPlaceholder অ্যাট্রিবিউট অথবা SplitPlaceholder.Builder এর setSticky() মেথড ডিফল্ট আচরণকে ওভাররাইড করতে পারে। যখন অ্যাট্রিবিউট বা মেথড true এর মান নির্দিষ্ট করে, তখন সিস্টেমটি টাস্ক উইন্ডোতে প্লেসহোল্ডারকে সর্বোচ্চ অ্যাক্টিভিটি হিসেবে প্রদর্শন করে যখন ডিসপ্লেটিকে দুই-প্যান ডিসপ্লে থেকে একক-প্যান ডিসপ্লেতে পুনরায় আকার দেওয়া হয় (উদাহরণস্বরূপ Split কনফিগারেশন দেখুন)।

জানালার আকার পরিবর্তন
যখন ডিভাইস কনফিগারেশন পরিবর্তনের ফলে টাস্ক উইন্ডোর প্রস্থ এতটাই কমিয়ে দেওয়া হয় যে এটি মাল্টি-প্যান লেআউটের জন্য যথেষ্ট বড় হয় না (উদাহরণস্বরূপ, যখন একটি বড় স্ক্রিনের ফোল্ডেবল ডিভাইস ট্যাবলেটের আকার থেকে ফোনের আকারে ভাঁজ করা হয় বা অ্যাপ উইন্ডোটি মাল্টি-উইন্ডো মোডে পুনরায় আকার দেওয়া হয়), তখন টাস্ক উইন্ডোর সেকেন্ডারি প্যানে নন-প্লেসহোল্ডার অ্যাক্টিভিটিগুলি প্রাইমারি প্যানের অ্যাক্টিভিটির উপরে স্ট্যাক করা হয়।
প্লেসহোল্ডার কার্যকলাপগুলি কেবল তখনই দেখানো হয় যখন একটি বিভক্তির জন্য পর্যাপ্ত প্রদর্শন প্রস্থ থাকে। ছোট স্ক্রিনে, প্লেসহোল্ডারটি স্বয়ংক্রিয়ভাবে বাতিল হয়ে যায়। যখন প্রদর্শনের ক্ষেত্রটি আবার যথেষ্ট বড় হয়ে যায়, তখন প্লেসহোল্ডারটি পুনরায় তৈরি করা হয়। ( প্লেসহোল্ডার বিভাগটি দেখুন।)
অ্যাক্টিভিটি স্ট্যাকিং সম্ভব কারণ WindowManager z-প্রাইমারি প্যানে থাকা অ্যাক্টিভিটির উপরে সেকেন্ডারি প্যানে থাকা অ্যাক্টিভিটির অর্ডার দেয়।
সেকেন্ডারি প্যানে একাধিক কার্যকলাপ
অ্যাক্টিভিটি B কোনও অতিরিক্ত ইনটেন্ট ফ্ল্যাগ ছাড়াই অ্যাক্টিভিটি C শুরু করে:

একই কাজে নিম্নলিখিত z-ক্রমের কার্যকলাপ তৈরি হয়:

সুতরাং, একটি ছোট টাস্ক উইন্ডোতে, অ্যাপ্লিকেশনটি স্ট্যাকের শীর্ষে C সহ একটি একক কার্যকলাপে সঙ্কুচিত হয়:

ছোট উইন্ডোতে ফিরে গেলে একে অপরের উপরে স্তূপীকৃত কার্যকলাপগুলি নেভিগেট করা হয়।
যদি টাস্ক উইন্ডো কনফিগারেশনটি আরও বড় আকারে পুনরুদ্ধার করা হয় যা একাধিক প্যান ধারণ করতে পারে, তাহলে কার্যকলাপগুলি আবার পাশাপাশি প্রদর্শিত হবে।
স্ট্যাকড স্প্লিট
কার্যকলাপ B, কার্যকলাপ C কে পাশে শুরু করে এবং বিভক্তিকে পাশে সরিয়ে দেয়:

ফলাফল হল একই কাজে নিম্নলিখিত z-ক্রমের কার্যকলাপ:

একটি ছোট টাস্ক উইন্ডোতে, অ্যাপ্লিকেশনটি C এর উপরে থাকা একক কার্যকলাপে সঙ্কুচিত হয়:

স্থির-প্রতিকৃতি অভিযোজন
অ্যান্ড্রয়েড:স্ক্রিনওরিয়েন্টেশন ম্যানিফেস্ট সেটিং অ্যাপগুলিকে কার্যকলাপগুলিকে পোর্ট্রেট বা ল্যান্ডস্কেপ ওরিয়েন্টেশনের মধ্যে সীমাবদ্ধ করতে সক্ষম করে। ট্যাবলেট এবং ফোল্ডেবলের মতো বড় স্ক্রিন ডিভাইসে ব্যবহারকারীর অভিজ্ঞতা উন্নত করার জন্য, ডিভাইস নির্মাতারা (OEM) স্ক্রিন ওরিয়েন্টেশন অনুরোধ উপেক্ষা করতে পারে এবং ল্যান্ডস্কেপ ডিসপ্লেতে পোর্ট্রেট ওরিয়েন্টেশনে অ্যাপটিকে লেটারবক্স করতে পারে অথবা পোর্ট্রেট ডিসপ্লেতে ল্যান্ডস্কেপ ওরিয়েন্টেশনে রাখতে পারে।

একইভাবে, যখন অ্যাক্টিভিটি এম্বেডিং সক্ষম করা থাকে, তখন OEM গুলি বড় স্ক্রিনে (প্রস্থ ≥ 600dp) ল্যান্ডস্কেপ ওরিয়েন্টেশনে লেটারবক্স ফিক্সড-পোর্ট্রেট অ্যাক্টিভিটিগুলিতে ডিভাইসগুলিকে কাস্টমাইজ করতে পারে। যখন একটি ফিক্সড-পোর্ট্রেট অ্যাক্টিভিটি দ্বিতীয় অ্যাক্টিভিটি চালু করে, তখন ডিভাইসটি দুটি-প্যান ডিসপ্লেতে পাশাপাশি দুটি অ্যাক্টিভিটি প্রদর্শন করতে পারে।

আপনার অ্যাপ অ্যাক্টিভিটি এম্বেডিং সমর্থন করে এমন ডিভাইসগুলিকে জানানোর জন্য সর্বদা আপনার অ্যাপ ম্যানিফেস্ট ফাইলে android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED প্রপার্টি যোগ করুন ( স্প্লিট কনফিগারেশন বিভাগটি দেখুন)। OEM-কাস্টমাইজড ডিভাইসগুলি তখন স্থির-পোর্ট্রেট কার্যকলাপগুলিকে লেটারবক্স করবে কিনা তা নির্ধারণ করতে পারে।
বিভক্ত কনফিগারেশন
স্প্লিট রুলস অ্যাক্টিভিটি স্প্লিট কনফিগার করে। আপনি একটি XML কনফিগারেশন ফাইলে অথবা Jetpack WindowManager API কল করে স্প্লিট রুলস সংজ্ঞায়িত করতে পারেন।
উভয় ক্ষেত্রেই, আপনার অ্যাপটিকে অবশ্যই WindowManager লাইব্রেরি অ্যাক্সেস করতে হবে এবং সিস্টেমকে জানাতে হবে যে অ্যাপটি অ্যাক্টিভিটি এম্বেডিং বাস্তবায়ন করেছে।
নিম্নলিখিতগুলি করুন:
আপনার অ্যাপের মডিউল-স্তরের
build.gradleফাইলে সর্বশেষ WindowManager লাইব্রেরি নির্ভরতা যোগ করুন, উদাহরণস্বরূপ:implementation 'androidx.window:window:1.1.0-beta02'WindowManager লাইব্রেরি অ্যাক্টিভিটি এম্বেডিংয়ের জন্য প্রয়োজনীয় সমস্ত উপাদান সরবরাহ করে।
সিস্টেমকে জানান যে আপনার অ্যাপ অ্যাক্টিভিটি এম্বেডিং বাস্তবায়ন করেছে।
অ্যাপ ম্যানিফেস্ট ফাইলের <application> এলিমেন্টে
android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLEDপ্রোপার্টি যোগ করুন এবং মানটিকে true তে সেট করুন, উদাহরণস্বরূপ:<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application> <property android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED" android:value="true" /> </application> </manifest>WindowManager রিলিজ 1.1.0-alpha06 এবং পরবর্তী সংস্করণে, ম্যানিফেস্টে সম্পত্তি যোগ না করা এবং সত্যে সেট না করা হলে অ্যাক্টিভিটি এম্বেডিং স্প্লিটগুলি অক্ষম করা হয়।
এছাড়াও, ডিভাইস নির্মাতারা অ্যাক্টিভিটি এম্বেডিং সমর্থন করে এমন অ্যাপগুলির জন্য কাস্টম ক্ষমতা সক্ষম করার জন্য সেটিং ব্যবহার করে। উদাহরণস্বরূপ, ডিভাইসগুলি ল্যান্ডস্কেপ ডিসপ্লেতে একটি পোর্ট্রেট-অনলি অ্যাক্টিভিটি লেটারবক্স করতে পারে যাতে দ্বিতীয় অ্যাক্টিভিটি শুরু হলে দুই-প্যান লেআউটে রূপান্তরের জন্য অ্যাক্টিভিটিটি ওরিয়েন্ট করা যায় ( স্থির-পোর্ট্রেট ওরিয়েন্টেশন দেখুন)।
XML কনফিগারেশন
অ্যাক্টিভিটি এম্বেডিংয়ের একটি XML-ভিত্তিক বাস্তবায়ন তৈরি করতে, নিম্নলিখিত পদক্ষেপগুলি সম্পূর্ণ করুন:
একটি XML রিসোর্স ফাইল তৈরি করুন যা নিম্নলিখিত কাজগুলি করে:
- একটি বিভক্তি ভাগ করে এমন কার্যকলাপগুলিকে সংজ্ঞায়িত করে
- বিভক্ত বিকল্পগুলি কনফিগার করে
- যখন কন্টেন্ট উপলব্ধ না থাকে তখন স্প্লিটের সেকেন্ডারি কন্টেইনারের জন্য একটি প্লেসহোল্ডার তৈরি করে।
- এমন কার্যকলাপ নির্দিষ্ট করে যা কখনই বিভক্তির অংশ হওয়া উচিত নয়
উদাহরণস্বরূপ:
<!-- main_split_config.xml --> <resources xmlns:window="http://schemas.android.com/apk/res-auto"> <!-- Define a split for the named activities. --> <SplitPairRule window:splitRatio="0.33" window:splitLayoutDirection="locale" window:splitMinWidthDp="840" window:splitMaxAspectRatioInPortrait="alwaysAllow" window:finishPrimaryWithSecondary="never" window:finishSecondaryWithPrimary="always" window:clearTop="false"> <SplitPairFilter window:primaryActivityName=".ListActivity" window:secondaryActivityName=".DetailActivity"/> </SplitPairRule> <!-- Specify a placeholder for the secondary container when content is not available. --> <SplitPlaceholderRule window:placeholderActivityName=".PlaceholderActivity" window:splitRatio="0.33" window:splitLayoutDirection="locale" window:splitMinWidthDp="840" window:splitMaxAspectRatioInPortrait="alwaysAllow" window:stickyPlaceholder="false"> <ActivityFilter window:activityName=".ListActivity"/> </SplitPlaceholderRule> <!-- Define activities that should never be part of a split. Note: Takes precedence over other split rules for the activity named in the rule. --> <ActivityRule window:alwaysExpand="true"> <ActivityFilter window:activityName=".ExpandedActivity"/> </ActivityRule> </resources>একটি ইনিশিয়েলাইজার তৈরি করুন।
WindowManager
RuleControllerকম্পোনেন্ট XML কনফিগারেশন ফাইল পার্স করে এবং সিস্টেমে নিয়মগুলি উপলব্ধ করে। একটি Jetpack Startup লাইব্রেরিInitializerঅ্যাপ স্টার্টআপের সময়RuleControllerকাছে XML ফাইলটি উপলব্ধ করে যাতে যেকোনো কার্যকলাপ শুরু হলে নিয়মগুলি কার্যকর থাকে।একটি ইনিশিয়ালাইজার তৈরি করতে, নিম্নলিখিতগুলি করুন:
আপনার মডিউল-স্তরের
build.gradleফাইলে সর্বশেষ Jetpack Startup লাইব্রেরি নির্ভরতা যোগ করুন, উদাহরণস্বরূপ:implementation 'androidx.startup:startup-runtime:1.1.1'একটি ক্লাস তৈরি করুন যা
Initializerইন্টারফেস বাস্তবায়ন করে।ইনিশিয়ালাইজার XML কনফিগারেশন ফাইলের (
main_split_config.xml) আইডিRuleController.parseRules()পদ্ধতিতে পাস করেRuleControllerকাছে স্প্লিট রুলস উপলব্ধ করে।কোটলিন
class SplitInitializer : Initializer<RuleController> { override fun create(context: Context): RuleController { return RuleController.getInstance(context).apply { setRules(RuleController.parseRules(context, R.xml.main_split_config)) } } override fun dependencies(): List<Class<out Initializer<*>>> { return emptyList() } }
জাভা
public class SplitInitializer implements Initializer<RuleController> { @NonNull @Override public RuleController create(@NonNull Context context) { RuleController ruleController = RuleController.getInstance(context); ruleController.setRules( RuleController.parseRules(context, R.xml.main_split_config) ); return ruleController; } @NonNull @Override public List<Class<? extends Initializer<?>>> dependencies() { return Collections.emptyList(); } }
নিয়ম সংজ্ঞার জন্য একটি কন্টেন্ট প্রদানকারী তৈরি করুন।
আপনার অ্যাপ ম্যানিফেস্ট ফাইলে
androidx.startup.InitializationProvider<provider>হিসেবে যোগ করুন। আপনারRuleControllerinitializer,SplitInitializerএর বাস্তবায়নের একটি রেফারেন্স অন্তর্ভুক্ত করুন:<!-- AndroidManifest.xml --> <provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" android:exported="false" tools:node="merge"> <!-- Make SplitInitializer discoverable by InitializationProvider. --> <meta-data android:name="${applicationId}.SplitInitializer" android:value="androidx.startup" /> </provider>অ্যাপের
onCreate()পদ্ধতি কল করার আগেInitializationProviderSplitInitializerআবিষ্কার করে এবং চালু করে। ফলস্বরূপ, অ্যাপের প্রধান কার্যকলাপ শুরু হলে split নিয়ম কার্যকর হয়।
উইন্ডো ম্যানেজার এপিআই
আপনি কয়েকটি API কলের মাধ্যমে প্রোগ্রাম্যাটিকভাবে অ্যাক্টিভিটি এম্বেডিং বাস্তবায়ন করতে পারেন। যেকোনো অ্যাক্টিভিটি চালু হওয়ার আগে নিয়মগুলি কার্যকর আছে কিনা তা নিশ্চিত করার জন্য Application একটি সাবক্লাসের onCreate() পদ্ধতিতে কলগুলি করুন।
প্রোগ্রাম্যাটিকভাবে একটি কার্যকলাপ বিভাজন তৈরি করতে, নিম্নলিখিতগুলি করুন:
একটি বিভক্ত নিয়ম তৈরি করুন:
একটি
SplitPairFilterতৈরি করুন যা স্প্লিট ভাগ করে নেওয়া কার্যকলাপগুলিকে চিহ্নিত করে:কোটলিন
val splitPairFilter = SplitPairFilter( ComponentName(this, ListActivity::class.java), ComponentName(this, DetailActivity::class.java), null )
জাভা
SplitPairFilter splitPairFilter = new SplitPairFilter( new ComponentName(this, ListActivity.class), new ComponentName(this, DetailActivity.class), null );
ফিল্টার সেটে ফিল্টারটি যোগ করুন:
```কোটলিন
val filterSet = setOf(splitPairFilter)
জাভা
Set<SplitPairFilter> filterSet = new HashSet<>(); filterSet.add(splitPairFilter);
বিভক্তির জন্য লেআউট বৈশিষ্ট্য তৈরি করুন:
কোটলিন
val splitAttributes: SplitAttributes = SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.33f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) .build()
জাভা
SplitAttributes splitAttributes = new SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.33f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) .build();
SplitAttributes.Builderলেআউট বৈশিষ্ট্য ধারণকারী একটি অবজেক্ট তৈরি করে:-
setSplitType(): প্রতিটি অ্যাক্টিভিটি কন্টেইনারে উপলব্ধ ডিসপ্লে এরিয়া কীভাবে বরাদ্দ করা হবে তা নির্ধারণ করে। রেশিও স্প্লিট টাইপ প্রাথমিক কন্টেইনারে বরাদ্দ করা উপলব্ধ ডিসপ্লে এরিয়ার অনুপাত নির্দিষ্ট করে; সেকেন্ডারি কন্টেইনারটি উপলব্ধ ডিসপ্লে এরিয়ার বাকি অংশ দখল করে। -
setLayoutDirection(): অ্যাক্টিভিটি কন্টেইনারগুলি একে অপরের সাপেক্ষে কীভাবে সাজানো হয় তা নির্দিষ্ট করে, প্রথমে প্রাথমিক কন্টেইনার।
-
একটি
SplitPairRuleতৈরি করুন:কোটলিন
val splitPairRule = SplitPairRule.Builder(filterSet) .setDefaultSplitAttributes(splitAttributes) .setMinWidthDp(840) .setMinSmallestWidthDp(600) .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f)) .setFinishPrimaryWithSecondary(SplitRule.FinishBehavior.NEVER) .setFinishSecondaryWithPrimary(SplitRule.FinishBehavior.ALWAYS) .setClearTop(false) .build()
জাভা
SplitPairRule splitPairRule = new SplitPairRule.Builder(filterSet) .setDefaultSplitAttributes(splitAttributes) .setMinWidthDp(840) .setMinSmallestWidthDp(600) .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f)) .setFinishPrimaryWithSecondary(SplitRule.FinishBehavior.NEVER) .setFinishSecondaryWithPrimary(SplitRule.FinishBehavior.ALWAYS) .setClearTop(false) .build();
SplitPairRule.Builderনিয়মটি তৈরি এবং কনফিগার করে:-
filterSet: স্প্লিট পেয়ার ফিল্টার ধারণ করে যা স্প্লিট ভাগ করে এমন কার্যকলাপগুলি সনাক্ত করে নিয়মটি কখন প্রয়োগ করতে হবে তা নির্ধারণ করে। -
setDefaultSplitAttributes(): নিয়মে লেআউট অ্যাট্রিবিউট প্রয়োগ করে। -
setMinWidthDp(): ন্যূনতম ডিসপ্লে প্রস্থ (ঘনত্ব-স্বাধীন পিক্সেল, dp) সেট করে যা একটি বিভক্তিকে সক্ষম করে। -
setMinSmallestWidthDp(): ডিভাইসের ওরিয়েন্টেশন নির্বিশেষে একটি স্প্লিট সক্ষম করার জন্য দুটি ডিসপ্লে ডাইমেনশনের মধ্যে ছোটটির ন্যূনতম মান (dp তে) সেট করে। -
setMaxAspectRatioInPortrait(): পোর্ট্রেট ওরিয়েন্টেশনে সর্বাধিক ডিসপ্লে অ্যাস্পেক্ট রেশিও (উচ্চতা:প্রস্থ) সেট করে যার জন্য অ্যাক্টিভিটি স্প্লিট প্রদর্শিত হয়। যদি কোনও পোর্ট্রেট ডিসপ্লের অ্যাস্পেক্ট রেশিও সর্বাধিক অ্যাস্পেক্ট রেশিও অতিক্রম করে, তাহলে ডিসপ্লের প্রস্থ নির্বিশেষে স্প্লিটগুলি অক্ষম করা হয়। দ্রষ্টব্য: ডিফল্ট মান হল 1.4, যার ফলে বেশিরভাগ ট্যাবলেটে পোর্ট্রেট ওরিয়েন্টেশনে অ্যাক্টিভিটিগুলি পুরো টাস্ক উইন্ডো দখল করে। আরও দেখুনSPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULTএবংsetMaxAspectRatioInLandscape()। ল্যান্ডস্কেপের জন্য ডিফল্ট মান হলALWAYS_ALLOW। -
setFinishPrimaryWithSecondary(): সেকেন্ডারি কন্টেইনারের সকল অ্যাক্টিভিটি শেষ করার ফলে প্রাইমারি কন্টেইনারের অ্যাক্টিভিটি কীভাবে প্রভাবিত হয় তা সেট করে।NEVERনির্দেশ করে যে সেকেন্ডারি কন্টেইনারের সকল অ্যাক্টিভিটি শেষ হয়ে গেলে সিস্টেমের প্রাইমারি অ্যাক্টিভিটি শেষ করা উচিত নয় ( Finish activities দেখুন)। -
setFinishSecondaryWithPrimary(): প্রাথমিক কন্টেইনারের সমস্ত কার্যকলাপ সমাপ্ত করলে তা সেকেন্ডারি কন্টেইনারের কার্যকলাপকে কীভাবে প্রভাবিত করে তা নির্ধারণ করে।ALWAYSনির্দেশ করে যে প্রাথমিক কন্টেইনারের সমস্ত কার্যকলাপ শেষ হলে সিস্টেমটি সর্বদা সেকেন্ডারি কন্টেইনারের কার্যকলাপ সমাপ্ত করবে ( Finish activities দেখুন)। -
setClearTop(): কন্টেইনারে নতুন অ্যাক্টিভিটি চালু হলে সেকেন্ডারি কন্টেইনারের সমস্ত অ্যাক্টিভিটি শেষ হয়েছে কিনা তা নির্দিষ্ট করে। একটিfalseমান নির্দেশ করে যে নতুন অ্যাক্টিভিটিগুলি সেকেন্ডারি কন্টেইনারে ইতিমধ্যে থাকা অ্যাক্টিভিটির উপরে স্ট্যাক করা হয়েছে।
-
WindowManager
RuleControllerএর সিঙ্গেলটন উদাহরণটি পান এবং নিয়মটি যোগ করুন:কোটলিন
val ruleController = RuleController.getInstance(this) ruleController.addRule(splitPairRule)
জাভা
RuleController ruleController = RuleController.getInstance(this); ruleController.addRule(splitPairRule);
যখন কন্টেন্ট উপলব্ধ না থাকে তখন সেকেন্ডারি কন্টেইনারের জন্য একটি প্লেসহোল্ডার তৈরি করুন:
একটি
ActivityFilterতৈরি করুন যা প্লেসহোল্ডার কোন কার্যকলাপটির সাথে একটি টাস্ক উইন্ডো বিভক্ত করে তা সনাক্ত করে:কোটলিন
val placeholderActivityFilter = ActivityFilter( ComponentName(this, ListActivity::class.java), null )
জাভা
ActivityFilter placeholderActivityFilter = new ActivityFilter( new ComponentName(this, ListActivity.class), null );
ফিল্টার সেটে ফিল্টারটি যোগ করুন:
কোটলিন
val placeholderActivityFilterSet = setOf(placeholderActivityFilter)
জাভা
Set<ActivityFilter> placeholderActivityFilterSet = new HashSet<>(); placeholderActivityFilterSet.add(placeholderActivityFilter);
একটি
SplitPlaceholderRuleতৈরি করুন:কোটলিন
val splitPlaceholderRule = SplitPlaceholderRule.Builder( placeholderActivityFilterSet, Intent(context, PlaceholderActivity::class.java) ).setDefaultSplitAttributes(splitAttributes) .setMinWidthDp(840) .setMinSmallestWidthDp(600) .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f)) .setFinishPrimaryWithPlaceholder(SplitRule.FinishBehavior.ALWAYS) .setSticky(false) .build()
জাভা
SplitPlaceholderRule splitPlaceholderRule = new SplitPlaceholderRule.Builder( placeholderActivityFilterSet, new Intent(this, PlaceholderActivity.class) ).setDefaultSplitAttributes(splitAttributes) .setMinWidthDp(840) .setMinSmallestWidthDp(600) .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ratio(1.5f)) .setFinishPrimaryWithPlaceholder(SplitRule.FinishBehavior.ALWAYS) .setSticky(false) .build();
SplitPlaceholderRule.Builderনিয়মটি তৈরি এবং কনফিগার করে:-
placeholderActivityFilterSet: এমন অ্যাক্টিভিটি ফিল্টার থাকে যা প্লেসহোল্ডার অ্যাক্টিভিটি কোন অ্যাক্টিভিটির সাথে সম্পর্কিত তা চিহ্নিত করে নিয়মটি কখন প্রয়োগ করতে হবে তা নির্ধারণ করে। -
Intent: প্লেসহোল্ডার কার্যকলাপের লঞ্চ নির্দিষ্ট করে। -
setDefaultSplitAttributes(): নিয়মে লেআউট অ্যাট্রিবিউট প্রয়োগ করে। -
setMinWidthDp(): ন্যূনতম ডিসপ্লে প্রস্থ (ঘনত্ব-স্বাধীন পিক্সেলে, dp) সেট করে যা একটি বিভক্তির অনুমতি দেয়। -
setMinSmallestWidthDp(): ডিভাইসের ওরিয়েন্টেশন নির্বিশেষে দুটি ডিসপ্লে ডাইমেনশনের মধ্যে ছোটটির ন্যূনতম মান (dp তে) সেট করে যা বিভক্ত করার অনুমতি দেয়। -
setMaxAspectRatioInPortrait(): পোর্ট্রেট ওরিয়েন্টেশনে সর্বাধিক ডিসপ্লে অ্যাসপেক্ট রেশিও (উচ্চতা:প্রস্থ) সেট করে যার জন্য অ্যাক্টিভিটি স্প্লিট প্রদর্শিত হয়। দ্রষ্টব্য: ডিফল্ট মান হল 1.4, যার ফলে বেশিরভাগ ট্যাবলেটে পোর্ট্রেট ওরিয়েন্টেশনে অ্যাক্টিভিটিগুলি টাস্ক উইন্ডো পূরণ করে। আরও দেখুনSPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULTএবংsetMaxAspectRatioInLandscape()। ল্যান্ডস্কেপের জন্য ডিফল্ট মান হলALWAYS_ALLOW। -
setFinishPrimaryWithPlaceholder(): প্লেসহোল্ডার অ্যাক্টিভিটি কীভাবে সমাপ্তি প্রাথমিক কন্টেইনারের ক্রিয়াকলাপগুলিকে প্রভাবিত করে তা সেট করে। ALWAYS নির্দেশ করে যে প্লেসহোল্ডার শেষ হওয়ার পরে সিস্টেমটি সর্বদা প্রাথমিক কন্টেইনারের ক্রিয়াকলাপগুলি শেষ করবে ( Finish activities দেখুন)। -
setSticky(): প্লেসহোল্ডারটি পর্যাপ্ত ন্যূনতম প্রস্থের সাথে একটি স্প্লিটে উপস্থিত হওয়ার পরে ছোট ডিসপ্লেতে অ্যাক্টিভিটি স্ট্যাকের উপরে প্লেসহোল্ডার অ্যাক্টিভিটি প্রদর্শিত হবে কিনা তা নির্ধারণ করে।
-
WindowManager
RuleControllerএ নিয়মটি যোগ করুন:কোটলিন
ruleController.addRule(splitPlaceholderRule)
জাভা
ruleController.addRule(splitPlaceholderRule);
এমন কার্যকলাপ নির্দিষ্ট করুন যা কখনই বিভক্তির অংশ হওয়া উচিত নয়:
একটি
ActivityFilterতৈরি করুন যা এমন একটি কার্যকলাপ চিহ্নিত করে যা সর্বদা পুরো টাস্ক প্রদর্শন এলাকা দখল করে:কোটলিন
val expandedActivityFilter = ActivityFilter( ComponentName(this, ExpandedActivity::class.java), null )
জাভা
ActivityFilter expandedActivityFilter = new ActivityFilter( new ComponentName(this, ExpandedActivity.class), null );
ফিল্টার সেটে ফিল্টারটি যোগ করুন:
কোটলিন
val expandedActivityFilterSet = setOf(expandedActivityFilter)
জাভা
Set<ActivityFilter> expandedActivityFilterSet = new HashSet<>(); expandedActivityFilterSet.add(expandedActivityFilter);
একটি
ActivityRuleতৈরি করুন:কোটলিন
val activityRule = ActivityRule.Builder(expandedActivityFilterSet) .setAlwaysExpand(true) .build()
জাভা
ActivityRule activityRule = new ActivityRule.Builder( expandedActivityFilterSet ).setAlwaysExpand(true) .build();
ActivityRule.Builderনিয়মটি তৈরি এবং কনফিগার করে:-
expandedActivityFilterSet: এমন অ্যাক্টিভিটি ফিল্টার রয়েছে যা স্প্লিট থেকে বাদ দিতে চান এমন অ্যাক্টিভিটিগুলি সনাক্ত করে নিয়মটি কখন প্রয়োগ করতে হবে তা নির্ধারণ করে। -
setAlwaysExpand(): কার্যকলাপটি সম্পূর্ণ টাস্ক উইন্ডোটি পূরণ করবে কিনা তা নির্দিষ্ট করে।
-
WindowManager
RuleControllerএ নিয়মটি যোগ করুন:কোটলিন
ruleController.addRule(activityRule)
জাভা
ruleController.addRule(activityRule);
ক্রস-অ্যাপ্লিকেশন এম্বেডিং
অ্যান্ড্রয়েড ১৩ (এপিআই লেভেল ৩৩) এবং তার উচ্চতর সংস্করণে, অ্যাপগুলি অন্যান্য অ্যাপ থেকে কার্যকলাপ এম্বেড করতে পারে। ক্রস-অ্যাপ্লিকেশন, বা ক্রস- ইউআইডি , অ্যাক্টিভিটি এম্বেডিং একাধিক অ্যান্ড্রয়েড অ্যাপ্লিকেশন থেকে কার্যকলাপের ভিজ্যুয়াল ইন্টিগ্রেশন সক্ষম করে। সিস্টেমটি হোস্ট অ্যাপের একটি কার্যকলাপ এবং অন্য অ্যাপ থেকে একটি এমবেডেড কার্যকলাপ স্ক্রিনে পাশাপাশি বা উপরে এবং নীচে প্রদর্শন করে, ঠিক যেমন একক-অ্যাপ অ্যাক্টিভিটি এম্বেডিংয়ে হয়।
উদাহরণস্বরূপ, সেটিংস অ্যাপটি WallpaperPicker অ্যাপ থেকে ওয়ালপেপার নির্বাচক কার্যকলাপ এম্বেড করতে পারে:

বিশ্বাস মডেল
অন্যান্য অ্যাপ থেকে কার্যকলাপ এম্বেড করে এমন হোস্ট প্রক্রিয়াগুলি আকার, অবস্থান, ক্রপিং এবং স্বচ্ছতা সহ এমবেডেড কার্যকলাপগুলির উপস্থাপনাকে পুনরায় সংজ্ঞায়িত করতে সক্ষম। ক্ষতিকারক হোস্টগুলি ব্যবহারকারীদের বিভ্রান্ত করতে এবং ক্লিকজ্যাকিং বা অন্যান্য UI-রিড্রেসিং আক্রমণ তৈরি করতে এই ক্ষমতা ব্যবহার করতে পারে।
ক্রস-অ্যাপ অ্যাক্টিভিটি এম্বেডিংয়ের অপব্যবহার রোধ করতে, অ্যান্ড্রয়েড অ্যাপগুলিকে তাদের কার্যকলাপ এম্বেড করার অনুমতি দেওয়ার জন্য অপ্ট-ইন করতে বাধ্য করে। অ্যাপগুলি হোস্টগুলিকে বিশ্বস্ত বা অবিশ্বস্ত হিসাবে চিহ্নিত করতে পারে।
বিশ্বস্ত হোস্ট
অন্যান্য অ্যাপ্লিকেশনগুলিকে আপনার অ্যাপ থেকে কার্যকলাপের উপস্থাপনা এম্বেড করতে এবং সম্পূর্ণরূপে নিয়ন্ত্রণ করতে দেওয়ার জন্য, আপনার অ্যাপের ম্যানিফেস্ট ফাইলের <activity> অথবা <application> উপাদানগুলির android:knownActivityEmbeddingCerts অ্যাট্রিবিউটে হোস্ট অ্যাপ্লিকেশনের SHA-256 সার্টিফিকেট নির্দিষ্ট করুন।
android:knownActivityEmbeddingCerts এর মান স্ট্রিং হিসেবে সেট করুন:
<activity
android:name=".MyEmbeddableActivity"
android:knownActivityEmbeddingCerts="@string/known_host_certificate_digest"
... />
অথবা, একাধিক সার্টিফিকেট নির্দিষ্ট করতে, স্ট্রিংগুলির একটি অ্যারে:
<activity
android:name=".MyEmbeddableActivity"
android:knownActivityEmbeddingCerts="@array/known_host_certificate_digests"
... />
যা নিম্নলিখিতগুলির মতো একটি সম্পদের উল্লেখ করে:
<resources>
<string-array name="known_host_certificate_digests">
<item>cert1</item>
<item>cert2</item>
...
</string-array>
</resources>
অ্যাপ মালিকরা Gradle signingReport টাস্কটি চালিয়ে SHA সার্টিফিকেট ডাইজেস্ট পেতে পারেন। সার্টিফিকেট ডাইজেস্ট হল SHA-256 ফিঙ্গারপ্রিন্ট যা আলাদা কোলন ছাড়াই। আরও তথ্যের জন্য, Run a signing report এবং Authenticating Your Client দেখুন।
অবিশ্বস্ত হোস্ট
যেকোনো অ্যাপকে আপনার অ্যাপের কার্যকলাপ এম্বেড করতে এবং তাদের উপস্থাপনা নিয়ন্ত্রণ করতে দেওয়ার জন্য, অ্যাপ ম্যানিফেস্টে <activity> অথবা <application> উপাদানগুলিতে android:allowUntrustedActivityEmbedding অ্যাট্রিবিউটটি নির্দিষ্ট করুন, উদাহরণস্বরূপ:
<activity
android:name=".MyEmbeddableActivity"
android:allowUntrustedActivityEmbedding="true"
... />
অ্যাট্রিবিউটের ডিফল্ট মান মিথ্যা, যা ক্রস-অ্যাপ অ্যাক্টিভিটি এম্বেডিং প্রতিরোধ করে।
কাস্টম প্রমাণীকরণ
অবিশ্বস্ত কার্যকলাপ এম্বেডিংয়ের ঝুঁকি কমাতে, একটি কাস্টম প্রমাণীকরণ ব্যবস্থা তৈরি করুন যা হোস্ট পরিচয় যাচাই করে। যদি আপনি হোস্ট সার্টিফিকেটগুলি জানেন, তাহলে প্রমাণীকরণের জন্য androidx.security.app.authenticator লাইব্রেরি ব্যবহার করুন। যদি হোস্ট আপনার কার্যকলাপ এম্বেড করার পরে প্রমাণীকরণ করে, তাহলে আপনি প্রকৃত সামগ্রী প্রদর্শন করতে পারেন। যদি তা না হয়, তাহলে আপনি ব্যবহারকারীকে জানাতে পারেন যে ক্রিয়াকলাপটি অনুমোদিত ছিল না এবং সামগ্রীটি ব্লক করতে পারেন।
কোনও হোস্ট আপনার অ্যাক্টিভিটি এম্বেড করছে কিনা তা পরীক্ষা করতে Jetpack WindowManager লাইব্রেরি থেকে ActivityEmbeddingController#isActivityEmbedded() পদ্ধতিটি ব্যবহার করুন, উদাহরণস্বরূপ:
কোটলিন
fun isActivityEmbedded(activity: Activity): Boolean { return ActivityEmbeddingController.getInstance(this).isActivityEmbedded(activity) }
জাভা
boolean isActivityEmbedded(Activity activity) { return ActivityEmbeddingController.getInstance(context).isActivityEmbedded(activity); }
ন্যূনতম আকারের সীমাবদ্ধতা
অ্যান্ড্রয়েড সিস্টেম অ্যাপ ম্যানিফেস্টে <layout> এলিমেন্টে উল্লেখিত ন্যূনতম উচ্চতা এবং প্রস্থ এমবেডেড কার্যকলাপে প্রয়োগ করে। যদি কোনও অ্যাপ্লিকেশন ন্যূনতম উচ্চতা এবং প্রস্থ নির্দিষ্ট না করে, তাহলে সিস্টেমের ডিফল্ট মানগুলি প্রযোজ্য হয় ( sw220dp )।
যদি হোস্ট এমবেডেড কন্টেইনারটিকে সর্বনিম্ন আকারের চেয়ে ছোট আকারে আকার দেওয়ার চেষ্টা করে, তাহলে এমবেডেড কন্টেইনারটি পুরো টাস্ক সীমা দখল করার জন্য প্রসারিত হবে।
<ক্রিয়াকলাপ-উপনাম>
<activity-alias> এলিমেন্টের সাথে বিশ্বস্ত বা অবিশ্বস্ত অ্যাক্টিভিটি এম্বেডিং কাজ করার জন্য, android:knownActivityEmbeddingCerts অথবা android:allowUntrustedActivityEmbedding অবশ্যই এলিয়াসের পরিবর্তে টার্গেট অ্যাক্টিভিটিতে প্রয়োগ করতে হবে। সিস্টেম সার্ভারে নিরাপত্তা যাচাই করার নীতিটি এলিয়াসের পরিবর্তে টার্গেটের উপর সেট করা ফ্ল্যাগের উপর ভিত্তি করে তৈরি হয়।
হোস্ট অ্যাপ্লিকেশন
হোস্ট অ্যাপ্লিকেশনগুলি সিঙ্গেল-অ্যাপ অ্যাক্টিভিটি এম্বেডিং বাস্তবায়নের মতোই ক্রস-অ্যাপ অ্যাক্টিভিটি এম্বেডিং বাস্তবায়ন করে। SplitPairRule এবং SplitPairFilter অথবা ActivityRule এবং ActivityFilter অবজেক্টগুলি এম্বেডেড অ্যাক্টিভিটি এবং টাস্ক উইন্ডো স্প্লিট নির্দিষ্ট করে। স্প্লিট নিয়মগুলি XML-এ বা Jetpack WindowManager API কল ব্যবহার করে রানটাইমে স্ট্যাটিকভাবে সংজ্ঞায়িত করা হয়।
যদি কোনও হোস্ট অ্যাপ্লিকেশন এমন কোনও কার্যকলাপ এম্বেড করার চেষ্টা করে যা ক্রস-অ্যাপ এম্বেডিং বেছে নেয়নি, তাহলে কার্যকলাপটি পুরো টাস্ক সীমা দখল করে। ফলস্বরূপ, হোস্ট অ্যাপ্লিকেশনগুলিকে জানতে হবে যে লক্ষ্য কার্যকলাপগুলি ক্রস-অ্যাপ এম্বেডিং অনুমোদন করে কিনা।
যদি একটি এমবেডেড অ্যাক্টিভিটি একই টাস্কে একটি নতুন অ্যাক্টিভিটি শুরু করে এবং নতুন অ্যাক্টিভিটি ক্রস-অ্যাপ এম্বেডিং বেছে না নেয়, তাহলে অ্যাক্টিভিটিটি এমবেডেড কন্টেইনারে অ্যাক্টিভিটি ওভারলে করার পরিবর্তে পুরো টাস্ক সীমা দখল করে।
একটি হোস্ট অ্যাপ্লিকেশন তার নিজস্ব কার্যকলাপ কোনও বাধা ছাড়াই এম্বেড করতে পারে যতক্ষণ না কার্যকলাপগুলি একই কাজে চালু হয়।
উদাহরণ বিভক্ত করুন
সম্পূর্ণ উইন্ডো থেকে বিভক্ত করুন

কোনও রিফ্যাক্টরিং প্রয়োজন নেই। আপনি স্প্লিটের জন্য স্ট্যাটিক্যালি বা রানটাইমে কনফিগারেশন নির্ধারণ করতে পারেন এবং তারপরে কোনও অতিরিক্ত প্যারামিটার ছাড়াই Context#startActivity() কল করতে পারেন।
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
ডিফল্টভাবে বিভক্ত করুন
যখন কোনও অ্যাপ্লিকেশনের ল্যান্ডিং পৃষ্ঠাটি বড় স্ক্রিনে দুটি কন্টেইনারে বিভক্ত করার জন্য ডিজাইন করা হয়, তখন উভয় কার্যকলাপ একই সাথে তৈরি এবং উপস্থাপন করা হলে ব্যবহারকারীর অভিজ্ঞতা সবচেয়ে ভালো হয়। তবে, ব্যবহারকারী প্রাথমিক কন্টেইনারের কার্যকলাপের সাথে ইন্টারঅ্যাক্ট না করা পর্যন্ত স্প্লিটের সেকেন্ডারি কন্টেইনারের জন্য কন্টেন্ট উপলব্ধ নাও হতে পারে (উদাহরণস্বরূপ, ব্যবহারকারী একটি নেভিগেশন মেনু থেকে একটি আইটেম নির্বাচন করেন)। স্প্লিটের সেকেন্ডারি কন্টেইনারে কন্টেন্ট প্রদর্শিত না হওয়া পর্যন্ত একটি প্লেসহোল্ডার অ্যাক্টিভিটি শূন্যস্থান পূরণ করতে পারে ( প্লেসহোল্ডার বিভাগটি দেখুন)।

একটি প্লেসহোল্ডার দিয়ে একটি স্প্লিট তৈরি করতে, একটি প্লেসহোল্ডার তৈরি করুন এবং এটিকে প্রাথমিক কার্যকলাপের সাথে সংযুক্ত করুন:
<SplitPlaceholderRule
window:placeholderActivityName=".PlaceholderActivity">
<ActivityFilter
window:activityName=".MainActivity"/>
</SplitPlaceholderRule>
ডিপ লিঙ্ক স্প্লিট
যখন কোনও অ্যাপ কোনও ইনটেন্ট পায়, তখন টার্গেট অ্যাক্টিভিটি অ্যাক্টিভিটি স্প্লিটের সেকেন্ডারি অংশ হিসেবে দেখানো যেতে পারে; উদাহরণস্বরূপ, তালিকা থেকে কোনও আইটেম সম্পর্কে তথ্য সহ একটি বিস্তারিত স্ক্রিন দেখানোর অনুরোধ। ছোট ডিসপ্লেতে, বিস্তারিত সম্পূর্ণ টাস্ক উইন্ডোতে দেখানো হয়; বড় ডিভাইসে, তালিকার পাশে।

লঞ্চ অনুরোধটি মূল কার্যকলাপে পাঠানো উচিত, এবং লক্ষ্য বিশদ কার্যকলাপটি একটি বিভক্ত আকারে চালু করা উচিত। সিস্টেমটি স্বয়ংক্রিয়ভাবে উপলব্ধ প্রদর্শন প্রস্থের উপর ভিত্তি করে সঠিক উপস্থাপনাটি বেছে নেয়—স্ট্যাক করা বা পাশাপাশি—।
কোটলিন
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) RuleController.getInstance(this) .addRule(SplitPairRule.Builder(filterSet).build()) startActivity(Intent(this, DetailActivity::class.java)) }
জাভা
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); RuleController.getInstance(this) .addRule(new SplitPairRule.Builder(filterSet).build()); startActivity(new Intent(this, DetailActivity.class)); }
ডিপ লিঙ্ক ডেস্টিনেশনই হয়তো একমাত্র অ্যাক্টিভিটি যা ব্যবহারকারীর জন্য পিছনের নেভিগেশন স্ট্যাকে উপলব্ধ থাকা উচিত, এবং আপনি হয়তো বিস্তারিত অ্যাক্টিভিটি খারিজ করে শুধুমাত্র মূল অ্যাক্টিভিটি রেখে যাওয়া এড়াতে চাইবেন:


পরিবর্তে, আপনি finishPrimaryWithSecondary অ্যাট্রিবিউট ব্যবহার করে একই সময়ে উভয় কার্যকলাপ শেষ করতে পারেন:
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".ListActivity"
window:secondaryActivityName=".DetailActivity"/>
</SplitPairRule>
কনফিগারেশন বৈশিষ্ট্য বিভাগটি দেখুন।
বিভক্ত পাত্রে একাধিক কার্যকলাপ
একটি স্প্লিট কন্টেইনারে একাধিক অ্যাক্টিভিটি স্ট্যাক করলে ব্যবহারকারীরা ডিপ কন্টেন্ট অ্যাক্সেস করতে পারবেন। উদাহরণস্বরূপ, লিস্ট-ডিটেইল স্প্লিটের মাধ্যমে, ব্যবহারকারীকে একটি সাব-ডিটেইল বিভাগে যেতে হতে পারে কিন্তু প্রাথমিক অ্যাক্টিভিটি যথাস্থানে রাখতে হবে:

কোটলিন
class DetailActivity : AppCompatActivity() { fun onOpenSubdetail() { startActivity(Intent(this, SubdetailActivity::class.java)) } }
জাভা
public class DetailActivity extends AppCompatActivity { void onOpenSubdetail() { startActivity(new Intent(this, SubdetailActivity.class)); } }
সাব-ডিটেইল অ্যাক্টিভিটিটি ডিটেইল অ্যাক্টিভিটির উপরে রাখা হয়, এটি গোপন করে:

এরপর ব্যবহারকারী স্ট্যাকের মাধ্যমে নেভিগেট করে পূর্ববর্তী বিস্তারিত স্তরে ফিরে যেতে পারেন:

একই সেকেন্ডারি কন্টেইনারের একটি অ্যাক্টিভিটি থেকে অ্যাক্টিভিটি চালু করা হলে একে অপরের উপরে অ্যাক্টিভিটি স্ট্যাক করা ডিফল্ট আচরণ। একটি সক্রিয় স্প্লিটের মধ্যে প্রাথমিক কন্টেইনার থেকে চালু করা অ্যাক্টিভিটিগুলি অ্যাক্টিভিটি স্ট্যাকের উপরে থাকা সেকেন্ডারি কন্টেইনারেও শেষ হয়।
একটি নতুন কাজের কার্যকলাপ
যখন একটি স্প্লিট টাস্ক উইন্ডোতে থাকা কার্যকলাপগুলি একটি নতুন কার্যে কার্যকলাপ শুরু করে, তখন নতুন কার্যটি স্প্লিট অন্তর্ভুক্ত টাস্ক থেকে আলাদা থাকে এবং সম্পূর্ণ উইন্ডোতে প্রদর্শিত হয়। সাম্প্রতিক স্ক্রিন দুটি কাজ দেখায়: স্প্লিটের কার্য এবং নতুন কার্য।

কার্যকলাপ প্রতিস্থাপন
সেকেন্ডারি কন্টেইনার স্ট্যাকে অ্যাক্টিভিটিগুলি প্রতিস্থাপন করা যেতে পারে; উদাহরণস্বরূপ, যখন প্রাথমিক অ্যাক্টিভিটি টপ-লেভেল নেভিগেশনের জন্য ব্যবহৃত হয় এবং সেকেন্ডারি অ্যাক্টিভিটি একটি নির্বাচিত গন্তব্যস্থল। টপ-লেভেল নেভিগেশন থেকে প্রতিটি নির্বাচনের সেকেন্ডারি কন্টেইনারে একটি নতুন অ্যাক্টিভিটি শুরু করা উচিত এবং আগে থেকে থাকা অ্যাক্টিভিটি বা অ্যাক্টিভিটিগুলি সরিয়ে ফেলা উচিত।

If the app doesn't finish the activity in the secondary container when the navigation selection changes, back navigation might be confusing when the split is collapsed (when the device is folded). For example, if you have a menu in the primary pane and screens A and B stacked in the secondary pane, when the user folds the phone, B is on top of A, and A is on top of the menu. When the user navigates back from B, A appears instead of the menu.
Screen A must be removed from the back stack in such cases.

The default behavior when launching to the side in a new container over an existing split is to put the new secondary containers on top and retain the old ones in the back stack. You can configure the splits to clear the previous secondary containers with clearTop and launch new activities normally.
<SplitPairRule
window:clearTop="true">
<SplitPairFilter
window:primaryActivityName=".Menu"
window:secondaryActivityName=".ScreenA"/>
<SplitPairFilter
window:primaryActivityName=".Menu"
window:secondaryActivityName=".ScreenB"/>
</SplitPairRule>
কোটলিন
inner class MenuActivity : AppCompatActivity() { fun onMenuItemSelected(selectedMenuItem: Int) { startActivity(Intent(this, classForItem(selectedMenuItem))) } }
জাভা
public class MenuActivity extends AppCompatActivity{ void onMenuItemSelected(int selectedMenuItem) { startActivity(new Intent(this, classForItem(selectedMenuItem))); } }
Alternatively, use the same secondary activity, and from the primary (menu) activity send new intents that resolve to the same instance but trigger a state or UI update in the secondary container.
Multiple splits
Apps can provide multi-level deep navigation by launching additional activities to the side.
When an activity in a secondary container launches a new activity to the side, a new split is created over top of the existing split.

The back stack contains all activities that were previously opened, so users can navigate to the A/B split after finishing C.

To create a new split, launch the new activity to the side from the existing secondary container. Declare the configurations for both the A/B and B/C splits and launch activity C normally from B:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
<SplitPairFilter
window:primaryActivityName=".B"
window:secondaryActivityName=".C"/>
</SplitPairRule>
কোটলিন
class B : AppCompatActivity() { fun onOpenC() { startActivity(Intent(this, C::class.java)) } }
জাভা
public class B extends AppCompatActivity{ void onOpenC() { startActivity(new Intent(this, C.class)); } }
React to split state changes
Different activities in an app can have UI elements that perform the same function; for example, a control that opens a window containing account settings.

If two activities that have a UI element in common are in a split, it's redundant and perhaps confusing to show the element in both activities.

To know when activities are in a split, check the SplitController.splitInfoList flow or register a listener with SplitControllerCallbackAdapter for changes in the split state. Then, adjust the UI accordingly:
কোটলিন
val layout = layoutInflater.inflate(R.layout.activity_main, null) val view = layout.findViewById<View>(R.id.infoButton) lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { splitController.splitInfoList(this@SplitDeviceActivity) // The activity instance. .collect { list -> view.visibility = if (list.isEmpty()) View.VISIBLE else View.GONE } } }
জাভা
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); new SplitControllerCallbackAdapter(SplitController.getInstance(this)) .addSplitListener( this, Runnable::run, splitInfoList -> { View layout = getLayoutInflater().inflate(R.layout.activity_main, null); layout.findViewById(R.id.infoButton).setVisibility( splitInfoList.isEmpty() ? View.VISIBLE : View.GONE); }); }
Coroutines can be launched in any lifecycle state, but are typically launched in the STARTED state to conserve resources (see Use Kotlin coroutines with lifecycle-aware components for more information).
Callbacks can be made in any lifecycle state, including when an activity is stopped. Listeners should usually be registered in onStart() and unregistered in onStop() .
Full-window modal
Some activities block users from interacting with the application until a specified action is performed; for example, a login screen activity, policy acknowledgement screen, or error message. Modal activities should be prevented from appearing in a split.
An activity can be forced to always fill the task window by using the expand configuration:
<ActivityRule
window:alwaysExpand="true">
<ActivityFilter
window:activityName=".FullWidthActivity"/>
</ActivityRule>
Finish activities
Users can finish activities on either side of the split by swiping from the edge of the display:


If the device is set up to use the back button instead of gesture navigation, the input is sent to the focused activity—the activity that was touched or launched last.
The effect that finishing all activities in a container has on the opposing container depends on the split configuration.
Configuration attributes
You can specify split pair rule attributes to configure how finishing all activities on one side of the split affects the activities on the other side of the split. The attributes are:
-
window:finishPrimaryWithSecondary— How finishing all activities in the secondary container affects the activities in the primary container -
window:finishSecondaryWithPrimary— How finishing all activities in the primary container affects the activities in the secondary container
Possible values of the attributes include:
-
always— Always finish the activities in the associated container -
never— Never finish the activities in the associated container -
adjacent— Finish the activities in the associated container when the two containers are displayed adjacent to each other, but not when the two containers are stacked
উদাহরণস্বরূপ:
<SplitPairRule
<!-- Do not finish primary container activities when all secondary container activities finish. -->
window:finishPrimaryWithSecondary="never"
<!-- Finish secondary container activities when all primary container activities finish. -->
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
Default configuration
When all activities in one container of a split finish, the remaining container occupies the entire window:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>


Finish activities together
Finish the activities in the primary container automatically when all activities in the secondary container finish:
<SplitPairRule
window:finishPrimaryWithSecondary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>


Finish the activities in the secondary container automatically when all activities in the primary container finish:
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>


Finish activities together when all activities in either the primary or secondary container finish:
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>


Finish multiple activities in containers
If multiple activities are stacked in a split container, finishing an activity on the bottom of the stack does not automatically finish activities on top.
For example, if two activities are in the secondary container, C on top of B:

and the configuration of the split is defined by the configuration of activities A and B:
<SplitPairRule>
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>
finishing the top activity retains the split.

Finishing the bottom (root) activity of the secondary container does not remove the activities on top of it; and so, also retains the split.

Any additional rules for finishing activities together, such as finishing the secondary activity with the primary, are also executed:
<SplitPairRule
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>

And when the split is configured to finish primary and secondary together:
<SplitPairRule
window:finishPrimaryWithSecondary="always"
window:finishSecondaryWithPrimary="always">
<SplitPairFilter
window:primaryActivityName=".A"
window:secondaryActivityName=".B"/>
</SplitPairRule>



Change split properties at runtime
The properties of an active and visible split cannot be changed. Changing the split rules affects additional activity launches and new containers, but not existing and active splits.
To change the properties of active splits, finish the side activity or activities in the split and launch to the side again with a new configuration.
Dynamic split properties
Android 15 (API level 35) and higher supported by Jetpack WindowManager 1.4 and higher offer dynamic features that enable configurability of activity embedding splits, including:
- Pane expansion: An interactive, draggable divider enables users to resize the panes in a split presentation.
- Activity stack pinning: Users can pin the content in one container and isolate navigation in the container from navigation in the other container.
- Dialog full-screen dim: When displaying a dialog, apps can specify whether to dim the entire task window or just the container that opened the dialog.
Pane expansion
Pane expansion enables users to adjust the amount of screen space allocated to the two activities in a dual‑pane layout.
To customize the appearance of the window divider and set the divider's draggable range, do the following:
Create an instance of
DividerAttributesCustomize the divider attributes:
color: The color of the draggable pane separator.widthDp: The width of the draggable pane separator. Set toWIDTH_SYSTEM_DEFAULTto let the system determine the divider width.Drag range: The minimum percentage of the screen either pane can occupy. Can range from 0.33 to 0.66. Set to
DRAG_RANGE_SYSTEM_DEFAULTto let the system determine the drag range.
কোটলিন
val splitAttributesBuilder: SplitAttributes.Builder = SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.33f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) if (WindowSdkExtensions.getInstance().extensionVersion >= 6) { splitAttributesBuilder.setDividerAttributes( DividerAttributes.DraggableDividerAttributes.Builder() .setColor(getColor(R.color.divider_color)) .setWidthDp(4) .setDragRange(DividerAttributes.DragRange.DRAG_RANGE_SYSTEM_DEFAULT) .build() ) } val splitAttributes: SplitAttributes = splitAttributesBuilder.build()
জাভা
SplitAttributes.Builder splitAttributesBuilder = new SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.33f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT); if (WindowSdkExtensions.getInstance().getExtensionVersion() >= 6) { splitAttributesBuilder.setDividerAttributes( new DividerAttributes.DraggableDividerAttributes.Builder() .setColor(ContextCompat.getColor(this, R.color.divider_color)) .setWidthDp(4) .setDragRange(DividerAttributes.DragRange.DRAG_RANGE_SYSTEM_DEFAULT) .build() ); } SplitAttributes _splitAttributes = splitAttributesBuilder.build();
Activity stack pinning
Activity stack pinning enables users to pin one of the split windows so the activity stays as is while users navigate within the other window. Activity stack pinning provides an enhanced multitasking experience.
To enable activity stack pinning in your app, do the following:
Add a button to the layout file of the activity you want to pin, for example, the detail activity of an list‑detail layout:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/detailActivity" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" tools:context=".DetailActivity"> <TextView android:id="@+id/textViewItemDetail" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="36sp" android:textColor="@color/obsidian" app:layout_constraintBottom_toTopOf="@id/pinButton" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatButton android:id="@+id/pinButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/pin_this_activity" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/textViewItemDetail"/> </androidx.constraintlayout.widget.ConstraintLayout>In the
onCreate()method of the activity, set an onclick listener on the button:কোটলিন
val pinButton: Button = findViewById(R.id.pinButton) pinButton.setOnClickListener { val splitAttributes: SplitAttributes = SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.66f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) .build() val pinSplitRule = SplitPinRule.Builder() .setSticky(true) .setDefaultSplitAttributes(splitAttributes) .build() SplitController.getInstance(applicationContext) .pinTopActivityStack(taskId, pinSplitRule) }
জাভা
Button pinButton = findViewById(R.id.pinButton); pinButton.setOnClickListener( (view) -> { SplitAttributes splitAttributes = new SplitAttributes.Builder() .setSplitType(SplitAttributes.SplitType.ratio(0.66f)) .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT) .build(); SplitPinRule pinSplitRule = new SplitPinRule.Builder() .setSticky(true) .setDefaultSplitAttributes(splitAttributes) .build(); SplitController.getInstance(getApplicationContext()) .pinTopActivityStack(getTaskId(), pinSplitRule); });
Dialog full-screen dim
Activities typically dim their displays to draw attention to a dialog. In activity embedding, both panes of the dual‑pane display should dim, not just the pane containing the activity that opened the dialog, for a unified UI experience.
With WindowManager 1.4 and higher, the entire app window dims by default when a dialog opens (see EmbeddingConfiguration.DimAreaBehavior.ON_TASK ).
To dim only the container of the activity that opened the dialog, use EmbeddingConfiguration.DimAreaBehavior.ON_ACTIVITY_STACK .
Extract an activity from a split to full window
Create a new configuration that displays the side activity full window, and then relaunch the activity with an intent that resolves to the same instance.
Check for split support at runtime
Activity embedding is supported on Android 12L (API level 32) and higher, but is also available on some devices running earlier platform versions. To check at runtime for the availability of the feature, use the SplitController.splitSupportStatus property or SplitController.getSplitSupportStatus() method:
কোটলিন
if (SplitController.getInstance(this).splitSupportStatus == SplitController.SplitSupportStatus.SPLIT_AVAILABLE ) { // Device supports split activity features. }
জাভা
if (SplitController.getInstance(this).getSplitSupportStatus() == SplitController.SplitSupportStatus.SPLIT_AVAILABLE) { // Device supports split activity features. }
If splits are not supported, activities are launched on top of the activity stack (following the non-activity embedding model).
Prevent system override
The manufacturers of Android devices (original equipment manufacturers, or OEMs), can implement activity embedding as a function of the device system. The system specifies split rules for multi-activity apps, overriding the windowing behavior of the apps. The system override forces multi-activity apps into a system-defined activity embedding mode.
System activity embedding can enhance app presentation through multi-pane layouts, such as list-detail , without any changes to the app. However, the system's activity embedding might also cause incorrect app layouts, bugs, or conflicts with activity embedding implemented by the app.
Your app can prevent or permit system activity embedding by setting PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE in the app manifest file, for example:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<property
android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE"
android:value="true|false" />
</application>
</manifest>
The property name is defined in the Jetpack WindowManager WindowProperties object. Set the value to false if your app implements activity embedding, or if you want to otherwise prevent the system from applying its activity embedding rules to your app. Set the value to true to permit the system to apply system-defined activity embedding to your app.
Limitations, restrictions, and caveats
- Only the host app of the task, which is identified as the owner of the root activity in the task, can organize and embed other activities in the task. If activities that support embedding and splits run in a task that belongs to a different application, then embedding and splits will not work for those activities.
- Activities can only be organized within a single task. Launching an activity in a new task always puts it in a new expanded window outside of any existing splits.
- Only activities in the same process can be organized and put in a split. The
SplitInfocallback only reports activities that belong to the same process, since there is no way of knowing about activities in different processes. - Each pair or singular activity rule applies only to activity launches that happen after the rule has been registered. There is currently no way to update existing splits or their visual properties.
- The split pair filter configuration must match the intents used when launching activities completely. The matching occurs at the point when a new activity is started from the application process, so it might not know about component names that are resolved later in the system process when using implicit intents. If a component name is not known at the time of launch, a wildcard can be used instead ("*/*") and filtering can be performed based on intent action.
- There is currently no way to move activities between containers or in and out of splits after they were created. Splits are only created by the WindowManager library when new activities with matching rules are launched, and splits are destroyed when the last activity in a split container is finished.
- Activities can be relaunched when the configuration changes, so when a split is created or removed and activity bounds change, the activity can go through complete destruction of the previous instance and creation of the new one. As a result, app developers should be careful with things like launching new activities from lifecycle callbacks.
- Devices must include the window extensions interface to support activity embedding. Nearly all large screen devices running Android 12L (API level 32) or higher include the interface. However, some large screen devices that are not capable of running multiple activities don't include the window extensions interface. If a large screen device doesn't support multi-window mode, it might not support activity embedding.
Additional resources
- Codelabs:
- Learning pathway — Activity embedding
- Sample app — activity-embedding