সাম্প্রতিক স্ক্রিন

সাম্প্রতিক স্ক্রিন, যাকে ওভারভিউ স্ক্রিন, সাম্প্রতিক টাস্ক তালিকা বা সাম্প্রতিক অ্যাপ স্ক্রিনও বলা হয়, এটি একটি সিস্টেম-লেভেল UI যা সম্প্রতি অ্যাক্সেস করা অ্যাক্টিভিটি এবং টাস্ক তালিকাভুক্ত করে। ব্যবহারকারী তালিকাটি নেভিগেট করতে, আবার শুরু করার জন্য একটি টাস্ক বেছে নিতে বা তালিকা থেকে কোনও টাস্ক সোয়াইপ করে সরিয়ে দিতে পারেন।

সাম্প্রতিক স্ক্রিন ডকুমেন্ট-কেন্দ্রিক মডেল ব্যবহার করে—যা Android 5.0 (API লেভেল ২১)-এ চালু করা হয়েছে—যেখানে বিভিন্ন ডকুমেন্ট সহ একই অ্যাক্টিভিটির একাধিক ইনস্ট্যান্স সাম্প্রতিক স্ক্রিনে টাস্ক হিসেবে দেখা যেতে পারে। যেমন, Google Drive-এ একাধিক Google ডকুমেন্টের প্রতিটির জন্য একটি করে টাস্ক থাকতে পারে। প্রতিটি ডকুমেন্ট 'সাম্প্রতিক' স্ক্রিনে একটি টাস্ক হিসেবে দেখা যায়:

'সাম্প্রতিক' স্ক্রিনে দুটি Google Drive ডকুমেন্ট দেখাচ্ছে, প্রতিটি আলাদা টাস্ক হিসেবে দেখানো হয়েছে।

আরেকটি সাধারণ উদাহরণ হল, ব্যবহারকারী তার ব্রাউজার ব্যবহার করার সময় শেয়ার করুন > Gmail বিকল্পে ট্যাপ করেন। Gmail অ্যাপের কম্পোজ স্ক্রিন দেখা যাবে। সেই সময় 'সাম্প্রতিক' বোতামে ট্যাপ করলে দেখা যাবে যে Chrome ও Gmail আলাদা টাস্ক হিসেবে চলছে:

সাম্প্রতিক স্ক্রিনে Chrome ও Gmail আলাদা টাস্ক হিসেবে চলছে।

সাধারণত, আপনি সিস্টেমকে আপনার টাস্ক এবং অ্যাক্টিভিটিগুলি কীভাবে সাম্প্রতিক স্ক্রিনে উপস্থাপিত হবে তা নির্ধারণ করতে দেন। আপনাকে এই আচরণ পরিবর্তন করতে হবে না। তবে, আপনার অ্যাপ নির্ধারণ করতে পারে যে কীভাবে এবং কখন অ্যাক্টিভিটি সাম্প্রতিক স্ক্রিনে দেখানো হবে।

ActivityManager.AppTask ক্লাস আপনাকে টাস্ক ম্যানেজ করতে দেয় এবং Intent ক্লাসের অ্যাক্টিভিটি ফ্ল্যাগ আপনাকে নির্দিষ্ট করতে দেয় যে কখন সাম্প্রতিক স্ক্রিন থেকে কোনও অ্যাক্টিভিটি যোগ করা বা সরানো হয়েছে। এছাড়াও, <activity> অ্যাট্রিবিউট আপনাকে ম্যানিফেস্টে আচরণ সেট করতে দেয়।

'সাম্প্রতিক' স্ক্রিনে টাস্ক যোগ করা

Intent ক্লাসের ফ্ল্যাগ ব্যবহার করে টাস্ক যোগ করলে, 'সাম্প্রতিক' স্ক্রিনে কোনও ডকুমেন্ট কখন ও কীভাবে খোলা বা আবার খোলা হবে, তার উপর আপনার আরও বেশি নিয়ন্ত্রণ থাকে। আপনি <activity> অ্যাট্রিবিউট ব্যবহার করলে, সবসময় নতুন টাস্কে ডকুমেন্ট খোলা অথবা ডকুমেন্টের জন্য আগে থেকে থাকা টাস্ক আবার ব্যবহার করার মধ্যে বেছে নিতে পারবেন।

টাস্ক যোগ করতে ইনটেন্ট ফ্ল্যাগ ব্যবহার করুন

আপনার অ্যাক্টিভিটির জন্য নতুন ডকুমেন্ট তৈরি করার সময়, আপনি startActivity() মেথড কল করেন, যা অ্যাক্টিভিটি চালু করার ইনটেন্ট পাস করে। একটি লজিক্যাল ব্রেক যোগ করতে, যাতে সিস্টেম আপনার অ্যাক্টিভিটিকে 'সাম্প্রতিক' স্ক্রিনে একটি নতুন টাস্ক হিসেবে বিবেচনা করে, অ্যাক্টিভিটি লঞ্চ করে এমন Intent-এর addFlags() পদ্ধতিতে FLAG_ACTIVITY_NEW_DOCUMENT ফ্ল্যাগ পাস করুন।

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

private fun newDocumentIntent(context: Context): Intent =
    Intent(context, NewDocumentActivity::class.java).apply {
        addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT or Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)
        putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, documentCounter++)
    }

@Composable
fun CreateDocumentButton() {
    val context = LocalContext.current
    Button(
        onClick = {
            val intent = newDocumentIntent(context)
            // Add FLAG_ACTIVITY_MULTIPLE_TASK if needed based on state
            context.startActivity(intent)
        }
    ) {
        Text("Create New Document")
    }
}

প্রধান অ্যাক্টিভিটি নতুন অ্যাক্টিভিটি লঞ্চ করলে, সিস্টেম আগে থেকে থাকা টাস্কের মধ্যে এমন একটি টাস্ক খোঁজে যার ইনটেন্ট, অ্যাক্টিভিটির ইনটেন্ট কম্পোনেন্টের নাম ও ইনটেন্ট ডেটার সাথে ম্যাচ করে। টাস্কটি খুঁজে পাওয়া না গেলে অথবা ইনটেন্টে FLAG_ACTIVITY_MULTIPLE_TASK ফ্ল্যাগ থাকলে, অ্যাক্টিভিটিকে রুট হিসেবে ব্যবহার করে একটি নতুন টাস্ক তৈরি করা হয়।

সিস্টেম যদি এমন কোনও টাস্ক খুঁজে পায় যার ইনটেন্ট, ইনটেন্ট কম্পোনেন্টের নাম ও ইনটেন্ট ডেটার সাথে মিলে যায়, তাহলে এটি সেই টাস্ককে সামনে নিয়ে আসে এবং নতুন ইনটেন্ট onNewIntent()-এ পাস করে। নতুন অ্যাক্টিভিটি ইনটেন্ট পায় এবং 'সাম্প্রতিক' স্ক্রিনে নতুন ডকুমেন্ট তৈরি করে, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

class DocumentCentricActivity : ComponentActivity() {
    private var documentState by mutableStateOf(
        DocumentState(
            count = 0,
            textResId = R.string.hello_new_document_counter
        )
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val initialCount = intent.getIntExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0)

        documentState = documentState.copy(count = initialCount)

        setContent {
            MaterialTheme {
                DocumentScreen(
                    count = documentState.count,
                    textResId = documentState.textResId
                )
            }
        }
    }

    override fun onNewIntent(newIntent: Intent) {
        super.onNewIntent(newIntent)
        // If FLAG_ACTIVITY_MULTIPLE_TASK has not been used, this Activity is reused.
        documentState = documentState.copy(
            textResId = R.string.reusing_document_counter
        )
    }

    data class DocumentState(val count: Int, @StringRes val textResId: Int)

    companion object {
        const val KEY_EXTRA_NEW_DOCUMENT_COUNTER = "KEY_EXTRA_NEW_DOCUMENT_COUNTER"
    }
}

@Composable
fun DocumentScreen(count: Int, @StringRes textResId: Int) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center
    ) {
        // UI reacts to whichever string resource ID was passed down
        Text(text = stringResource(id = textResId))
        Spacer(modifier = Modifier.height(8.dp))
        Text(text = "Counter: $count")
    }
}

আগের কোডে, অ্যাক্টিভিটি OS-লেভেল রাউটিং (onCreate এবং onNewIntent) ম্যানেজ করে, যেখানে @Composable ফাংশন শুধুমাত্র প্রদত্ত অবস্থার উপর ভিত্তি করে UI রেন্ডার করার জন্য দায়ী।

টাস্ক যোগ করতে অ্যাক্টিভিটি অ্যাট্রিবিউট ব্যবহার করুন

এছাড়াও, কোনও অ্যাক্টিভিটি তার ম্যানিফেস্টে উল্লেখ করতে পারে যে এটি সবসময় <activity> অ্যাট্রিবিউট android:documentLaunchMode ব্যবহার করে নতুন টাস্কে লঞ্চ করে। এই অ্যাট্রিবিউটের চারটি ভ্যালু আছে, যা ব্যবহারকারী অ্যাপ্লিকেশন দিয়ে কোনও ডকুমেন্ট খুললে নিম্নলিখিত প্রভাব তৈরি করে:

intoExisting
অ্যাক্টিভিটিটি ডকুমেন্টের জন্য আগে থেকে থাকা টাস্ক আবার ব্যবহার করে। এটি FLAG_ACTIVITY_MULTIPLE_TASK ফ্ল্যাগ সেট না করে FLAG_ACTIVITY_NEW_DOCUMENT ফ্ল্যাগ সেট করার মতোই, যেমন টাস্ক যোগ করতে ইনটেন্ট ফ্ল্যাগ ব্যবহার করা বিভাগে বর্ণনা করা হয়েছে।
always
অ্যাক্টিভিটি ডকুমেন্টের জন্য নতুন টাস্ক তৈরি করে, এমনকি ডকুমেন্টটি আগে থেকেই খোলা থাকলেও। এই ভ্যালু ব্যবহার করা মানে হল FLAG_ACTIVITY_NEW_DOCUMENT এবং FLAG_ACTIVITY_MULTIPLE_TASK ফ্ল্যাগ সেট করা।
none
অ্যাক্টিভিটি ডকুমেন্টের জন্য নতুন টাস্ক তৈরি করে না। 'সাম্প্রতিক' স্ক্রিন অ্যাক্টিভিটিকে ডিফল্ট হিসেবে বিবেচনা করে। এটি অ্যাপের জন্য একটি টাস্ক দেখায়, যা ব্যবহারকারীর শেষবার চালু করা অ্যাক্টিভিটি থেকে আবার শুরু হয়।
never
অ্যাক্টিভিটি ডকুমেন্টের জন্য নতুন টাস্ক তৈরি করে না। এই ভ্যালু সেট করলে FLAG_ACTIVITY_NEW_DOCUMENT এবং FLAG_ACTIVITY_MULTIPLE_TASK ফ্ল্যাগের আচরণ ওভাররাইড হয়ে যায়। ইনটেন্টে এর মধ্যে যেকোনও একটি সেট করা থাকলে এবং সাম্প্রতিক স্ক্রিনে অ্যাপের জন্য একটি টাস্ক দেখালে, ব্যবহারকারী শেষ যে অ্যাক্টিভিটি চালু করেছিলেন সেটি আবার শুরু হয়।

টাস্ক সরান

ডিফল্ট হিসেবে, কোনও ডকুমেন্ট টাস্কের অ্যাক্টিভিটি শেষ হয়ে গেলে, সেটি অটোমেটিক সাম্প্রতিক স্ক্রিন থেকে বেরিয়ে যায়। আপনি এই আচরণকে ActivityManager.AppTask ক্লাস, Intent ফ্ল্যাগ বা <activity> অ্যাট্রিবিউট দিয়ে ওভাররাইড করতে পারেন।

আপনি যেকোনও সময় <activity> অ্যাট্রিবিউট android:excludeFromRecents true-এ সেট করে সাম্প্রতিক স্ক্রিন থেকে কোনও টাস্ক সম্পূর্ণভাবে বাদ দিতে পারবেন।

আপনি <activity> অ্যাট্রিবিউট android:maxRecents-কে একটি ইনটিজার ভ্যালুতে সেট করে, আপনার অ্যাপ 'সাম্প্রতিক' স্ক্রিনে সর্বাধিক কতগুলি টাস্ক অন্তর্ভুক্ত করতে পারবে তা সেট করতে পারবেন। টাস্কের সর্বাধিক সংখ্যায় পৌঁছে গেলে, সবচেয়ে কম সম্প্রতি ব্যবহৃত টাস্কটি 'সাম্প্রতিক' স্ক্রিন থেকে অদৃশ্য হয়ে যায়। ডিফল্ট হল ১৬, এবং সর্বাধিক মান হল ৫০ (কম মেমরি ডিভাইসে ২৫)। ১-এর কম ভ্যালু সঠিক নয়।

টাস্ক সরাতে AppTask ক্লাস ব্যবহার করুন

সাম্প্রতিক স্ক্রিনে নতুন টাস্ক তৈরি করে এমন অ্যাক্টিভিটিতে, আপনি finishAndRemoveTask() মেথড কল করে টাস্কটি কখন সরাতে হবে এবং এর সাথে সম্পর্কিত সমস্ত অ্যাক্টিভিটি শেষ করতে হবে তা নির্দিষ্ট করতে পারেন:

@Composable
fun RemoveTaskButton() {
    val context = LocalContext.current
    Button(
        onClick = {
            // It is good practice to remove a document from the overview stack if not needed anymore.
            (context as? Activity)?.finishAndRemoveTask()
        }
    ) {
        Text("Remove from Recents")
    }
}

সম্পূর্ণ করা টাস্ক রেখে দিন

অ্যাক্টিভিটি শেষ হয়ে গেলেও, আপনি যদি 'সাম্প্রতিক' স্ক্রিনে কোনও টাস্ক রেখে দিতে চান, তাহলে যে ইনটেন্ট অ্যাক্টিভিটি লঞ্চ করে, তার addFlags() পদ্ধতিতে FLAG_ACTIVITY_RETAIN_IN_RECENTS ফ্ল্যাগ পাস করুন।

private fun newDocumentIntent() =
        Intent(this, NewDocumentActivity::class.java).apply {
            addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT or
                    android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)
            putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, getAndIncrement())
        }

একই এফেক্ট পেতে, <activity> অ্যাট্রিবিউট android:autoRemoveFromRecents false-এ সেট করুন। ডিফল্ট ভ্যালু হল ডকুমেন্ট অ্যাক্টিভিটির জন্য true এবং নিয়মিত অ্যাক্টিভিটির জন্য false। এই অ্যাট্রিবিউট ব্যবহার করলে FLAG_ACTIVITY_RETAIN_IN_RECENTS ফ্ল্যাগ ওভাররাইড হয়ে যায়।

সাম্প্রতিক URL শেয়ারিং চালু করুন (শুধুমাত্র Pixel-এ)

Android 12 বা তার পরবর্তী যেকোনও ভার্সনে রান করা Pixel ডিভাইসে, ব্যবহারকারীরা 'সাম্প্রতিক' স্ক্রিন থেকে সরাসরি সম্প্রতি দেখা ওয়েব কন্টেন্টের লিঙ্ক শেয়ার করতে পারবেন। অ্যাপে কন্টেন্ট দেখার পরে, ব্যবহারকারী 'সাম্প্রতিক' স্ক্রিনে সোয়াইপ করে সেই অ্যাপটি খুঁজে নিতে পারেন যেখানে তিনি কন্টেন্টটি দেখেছেন, তারপর URL কপি বা শেয়ার করতে লিঙ্ক বোতামে ট্যাপ করতে পারেন।

সম্প্রতি দেখা ওয়েব কন্টেন্ট শেয়ার করার লিঙ্ক সহ 'সাম্প্রতিক' স্ক্রিন।

যেকোনও অ্যাপ, ওয়েব UI প্রদান করে এবং onProvideAssistContent() ওভাররাইড করে ব্যবহারকারীদের জন্য 'সাম্প্রতিক' লিঙ্কিং চালু করতে পারে, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

class MainActivity : ComponentActivity() {

    // Track the current URL as state so the UI can update it during navigation
    private var currentWebUri by mutableStateOf("https://example.com/home")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            AppTheme {
                // Pass a lambda to your Compose UI so it can update the URL state
                // as the user navigates through your app.
                MainScreen(
                    onPageChanged = { newUrl -> currentWebUri = newUrl }
                )
            }
        }
    }

    override fun onProvideAssistContent(outContent: AssistContent) {
        super.onProvideAssistContent(outContent)

        // The system calls this when the user enters the Recents screen.
        // Provide the active URI tracked by the Compose state.
        outContent.webUri = Uri.parse(currentWebUri)
    }
}