আপনার ক্যামেরা অভিজ্ঞতা প্রকাশ করুন

1. আপনি শুরু করার আগে

Foldables সম্পর্কে বিশেষ কি?

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

পূর্বশর্ত

  • অ্যান্ড্রয়েড অ্যাপ তৈরির প্রাথমিক জ্ঞান
  • হিল্ট ডিপেনডেন্সি ইনজেকশন ফ্রেমওয়ার্কের প্রাথমিক জ্ঞান

আপনি কি নির্মাণ করবেন

এই কোডল্যাবে, আপনি ভাঁজযোগ্য ডিভাইসগুলির জন্য অপ্টিমাইজ করা লেআউট সহ একটি ক্যামেরা অ্যাপ তৈরি করেন।

6caebc2739522a1b.png

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

যদিও ক্যামেরা অ্যাপটি এই API-এর জন্য সবচেয়ে সুবিধাজনক ব্যবহারের ক্ষেত্রে, এই কোডল্যাবে আপনি যে বৈশিষ্ট্যগুলি শিখেন তা যে কোনও অ্যাপে প্রয়োগ করা যেতে পারে।

আপনি কি শিখবেন

  • ভঙ্গি পরিবর্তনের প্রতিক্রিয়া জানাতে জেটপ্যাক উইন্ডো ম্যানেজার কীভাবে ব্যবহার করবেন
  • কীভাবে আপনার অ্যাপটিকে একটি ফোল্ডেবলের ছোট ডিসপ্লেতে সরানো যায়

আপনি কি প্রয়োজন হবে

  • অ্যান্ড্রয়েড স্টুডিওর একটি সাম্প্রতিক সংস্করণ
  • একটি ভাঁজযোগ্য ডিভাইস বা ভাঁজযোগ্য এমুলেটর

2. সেট আপ করুন

শুরুর কোড পান

  1. আপনার যদি গিট ইনস্টল থাকে তবে আপনি কেবল নীচের কমান্ডটি চালাতে পারেন। গিট ইনস্টল করা আছে কিনা তা পরীক্ষা করতে, টার্মিনাল বা কমান্ড লাইনে git --version টাইপ করুন এবং এটি সঠিকভাবে কার্যকর হয়েছে কিনা তা যাচাই করুন।
git clone https://github.com/android/large-screen-codelabs.git
  1. ঐচ্ছিক: যদি আপনার কাছে গিট না থাকে, আপনি এই কোডল্যাবের সমস্ত কোড ডাউনলোড করতে নিম্নলিখিত বোতামে ক্লিক করতে পারেন:

প্রথম মডিউল খুলুন

  • অ্যান্ড্রয়েড স্টুডিওতে, /step1 অধীনে প্রথম মডিউলটি খুলুন।

অ্যান্ড্রয়েড স্টুডিওর স্ক্রিনশট এই কোডল্যাবের সাথে সম্পর্কিত কোড দেখাচ্ছে

যদি আপনাকে সর্বশেষ গ্রেডল সংস্করণ ব্যবহার করতে বলা হয়, এগিয়ে যান এবং এটি আপডেট করুন।

3. দৌড়ান এবং পর্যবেক্ষণ করুন

  1. মডিউল step1 এ কোডটি চালান।

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

a34aca632d75aa09.png

  1. এখন, ডিভাইসটিকে একটি অর্ধ-খোলা অবস্থানে রাখার চেষ্টা করুন, যেখানে কব্জাটি সম্পূর্ণ সমতল বা বন্ধ নয় তবে একটি 90-ডিগ্রি কোণ তৈরি করে।

আপনি দেখতে পাচ্ছেন, অ্যাপটি বিভিন্ন ডিভাইস ভঙ্গিতে সাড়া দেয় না এবং তাই বিন্যাস পরিবর্তন হয় না, ভিউফাইন্ডারের মাঝখানে কব্জা রেখে।

4. Jetpack WindowManager সম্পর্কে জানুন

Jetpack WindowManager লাইব্রেরি অ্যাপ ডেভেলপারদের ভাঁজযোগ্য ডিভাইসের জন্য অপ্টিমাইজ করা অভিজ্ঞতা তৈরি করতে সাহায্য করে। এটিতে FoldingFeature ক্লাস রয়েছে যা একটি নমনীয় ডিসপ্লেতে একটি ভাঁজ বা দুটি ফিজিক্যাল ডিসপ্লে প্যানেলের মধ্যে একটি কব্জা বর্ণনা করে। এর API ডিভাইস সম্পর্কিত গুরুত্বপূর্ণ তথ্য অ্যাক্সেস প্রদান করে:

FoldingFeature ক্লাসে অতিরিক্ত তথ্য রয়েছে, যেমন occlusionType() বা isSeparating() , কিন্তু এই কোডলেবে গভীরতার সাথে অন্বেষণ করে না।

সংস্করণ 1.2.0-beta01 থেকে শুরু করে, লাইব্রেরিটি WindowAreaController ব্যবহার করে, একটি API যা রিয়ার ডিসপ্লে মোডকে বর্তমান উইন্ডোটিকে রিয়ার ক্যামেরার সাথে সারিবদ্ধ ডিসপ্লেতে সরাতে সক্ষম করে, যা পিছনের ক্যামেরার সাথে সেলফি তোলার জন্য দুর্দান্ত এবং অনেকগুলি অন্যান্য ব্যবহারের ক্ষেত্রে!

নির্ভরতা যোগ করুন

  • আপনার অ্যাপে Jetpack WindowManager ব্যবহার করার জন্য, আপনাকে আপনার মডিউল-স্তরের build.gradle ফাইলে নিম্নলিখিত নির্ভরতা যোগ করতে হবে:

step1/build.gradle

def work_version = '1.2.0-beta01'
implementation "androidx.window:window:$work_version"
implementation "androidx.window:window-java:$work_version"
implementation "androidx.window:window-core:$work_version"

এখন আপনি আপনার অ্যাপে FoldingFeature এবং WindowAreaController উভয় ক্লাসই অ্যাক্সেস করতে পারবেন। আপনি চূড়ান্ত ভাঁজযোগ্য ক্যামেরা অভিজ্ঞতা তৈরি করতে এগুলি ব্যবহার করেন!

5. রিয়ার সেলফি মোড প্রয়োগ করুন৷

রিয়ার ডিসপ্লে মোড দিয়ে শুরু করুন।

যে APIটি এই মোডটিকে অনুমতি দেয় সেটি হল WindowAreaController , যা একটি ডিভাইসে প্রদর্শন বা প্রদর্শন অঞ্চলগুলির মধ্যে চলন্ত উইন্ডোগুলির চারপাশে তথ্য এবং আচরণ প্রদান করে৷

এটি আপনাকে WindowAreaInfo এর তালিকা অনুসন্ধান করতে দেয় যা বর্তমানে ইন্টারঅ্যাক্ট করার জন্য উপলব্ধ।

WindowAreaInfo ব্যবহার করে আপনি WindowAreaSession অ্যাক্সেস করতে পারেন, একটি সক্রিয় উইন্ডো এলাকা বৈশিষ্ট্য এবং একটি নির্দিষ্ট WindowAreaCapability.

  1. আপনার MainActivity তে এই ভেরিয়েবলগুলি ঘোষণা করুন:

step1/MainActivity.kt

private lateinit var windowAreaController: WindowAreaController
private lateinit var displayExecutor: Executor
private var rearDisplaySession: WindowAreaSession? = null
private var rearDisplayWindowAreaInfo: WindowAreaInfo? = null
private var rearDisplayStatus: WindowAreaCapability.Status =
    WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED
private val rearDisplayOperation = WindowAreaCapability.Operation.OPERATION_TRANSFER_ACTIVITY_TO_AREA
  1. এবং তাদের onCreate() পদ্ধতিতে আরম্ভ করুন:

step1/MainActivity.kt

displayExecutor = ContextCompat.getMainExecutor(this)
windowAreaController = WindowAreaController.getOrCreate()

lifecycleScope.launch(Dispatchers.Main) {
  lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
    windowAreaController.windowAreaInfos
      .map{info->info.firstOrNull{it.type==WindowAreaInfo.Type.TYPE_REAR_FACING}}
      .onEach { info -> rearDisplayWindowAreaInfo = info }
      .map{it?.getCapability(rearDisplayOperation)?.status?:  WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED }
      .distinctUntilChanged()
      .collect {
           rearDisplayStatus = it
           updateUI()
      }
  }
}
  1. এখন বর্তমান অবস্থার উপর নির্ভর করে, পিছনের সেলফি বোতামটি সক্ষম বা নিষ্ক্রিয় করতে updateUI() ফাংশনটি প্রয়োগ করুন:

step1/MainActivity.kt

private fun updateUI() {
    if(rearDisplaySession != null) {
        binding.rearDisplay.isEnabled = true
        // A session is already active, clicking on the button will disable it
    } else {
        when(rearDisplayStatus) {
            WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED -> {
                binding.rearDisplay.isEnabled = false
                // RearDisplay Mode is not supported on this device"
            }
            WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNAVAILABLE -> {
                binding.rearDisplay.isEnabled = false
                // RearDisplay Mode is not currently available
            }
            WindowAreaCapability.Status.WINDOW_AREA_STATUS_AVAILABLE -> {
                binding.rearDisplay.isEnabled = true
                // You can enable RearDisplay Mode
            }
            WindowAreaCapability.Status.WINDOW_AREA_STATUS_ACTIVE -> {
                binding.rearDisplay.isEnabled = true
                // You can disable RearDisplay Mode
            }
            else -> {
                binding.rearDisplay.isEnabled = false
                // RearDisplay status is unknown
            }
        }
    }
}

এই শেষ ধাপটি ঐচ্ছিক, কিন্তু একটি WindowAreaCapability.

  1. এখন toggleRearDisplayMode ফাংশনটি প্রয়োগ করুন, যা সেশনটি বন্ধ করে দেবে, যদি সক্ষমতা ইতিমধ্যে সক্রিয় থাকে, বা transferActivityToWindowArea ফাংশনটি কল করুন:

step1/CameraViewModel.kt

private fun toggleRearDisplayMode() {
    if(rearDisplayStatus == WindowAreaCapability.Status.WINDOW_AREA_STATUS_ACTIVE) {
        if(rearDisplaySession == null) {
            rearDisplaySession = rearDisplayWindowAreaInfo?.getActiveSession(rearDisplayOperation)
        }
        rearDisplaySession?.close()
    } else {
        rearDisplayWindowAreaInfo?.token?.let { token ->
            windowAreaController.transferActivityToWindowArea(
                token = token,
                activity = this,
                executor = displayExecutor,
                windowAreaSessionCallback = this
            )
        }
    }
}

একটি WindowAreaSessionCallback হিসাবে MainActivity এর ব্যবহার লক্ষ্য করুন।

রিয়ার ডিসপ্লে এপিআই একটি শ্রোতা পদ্ধতির সাথে কাজ করে: যখন আপনি বিষয়বস্তুটিকে অন্য ডিসপ্লেতে সরানোর অনুরোধ করেন, তখন আপনি একটি সেশন শুরু করেন যা শ্রোতার onSessionStarted() পদ্ধতির মাধ্যমে ফিরে আসে। আপনি যখন এর পরিবর্তে অভ্যন্তরীণ (এবং বড়) ডিসপ্লেতে ফিরে যেতে চান, আপনি সেশনটি বন্ধ করে দেন এবং আপনি onSessionEnded() পদ্ধতিতে একটি নিশ্চিতকরণ পান। এই ধরনের শ্রোতা তৈরি করতে, আপনাকে WindowAreaSessionCallback ইন্টারফেসটি বাস্তবায়ন করতে হবে।

  1. MainActivity ঘোষণা পরিবর্তন করুন যাতে এটি WindowAreaSessionCallback ইন্টারফেস প্রয়োগ করে:

step1/MainActivity.kt

class MainActivity : AppCompatActivity(), WindowAreaSessionCallback

এখন, MainActivity ভিতরে onSessionStarted এবং onSessionEnded পদ্ধতি প্রয়োগ করুন। সেশন স্ট্যাটাস সম্পর্কে বিজ্ঞপ্তি পেতে এবং সেই অনুযায়ী অ্যাপ আপডেট করার জন্য এই কলব্যাক পদ্ধতিগুলি অত্যন্ত কার্যকর।

কিন্তু এই সময়, সরলতার জন্য, শুধুমাত্র ফাংশন বডিতে কোন ত্রুটি আছে কিনা তা পরীক্ষা করুন এবং রাজ্য লগ করুন।

step1/MainActivity.kt

override fun onSessionEnded(t: Throwable?) {
    if(t != null) {
        Log.d("Something was broken: ${t.message}")
    }else{
        Log.d("rear session ended")
    }
}

override fun onSessionStarted(session: WindowAreaSession) {
    Log.d("rear session started [session=$session]")
}
  1. অ্যাপটি তৈরি করুন এবং চালান। তারপরে আপনি যদি আপনার ডিভাইসটি উন্মুক্ত করেন এবং পিছনের ডিসপ্লে বোতামে আলতো চাপেন, আপনাকে এইরকম একটি বার্তা দিয়ে অনুরোধ করা হবে:

3fa50cce0b0d4b8d.png

  1. আপনার সামগ্রী বাইরের ডিসপ্লেতে সরানো দেখতে " এখনই স্ক্রিনগুলি স্যুইচ করুন" নির্বাচন করুন!

6. ট্যাবলেটপ মোড প্রয়োগ করুন

এখন আপনার অ্যাপকে ভাঁজ-সচেতন করে তোলার সময়: আপনি ভাঁজের অভিযোজনের উপর ভিত্তি করে আপনার সামগ্রীটিকে ডিভাইসের কব্জাটির পাশে বা উপরে সরান৷ এটি করার জন্য, আপনি FoldingStateActor এর ভিতরে কাজ করবেন যাতে আপনার কোডটি সহজে পঠনযোগ্যতার জন্য Activity থেকে ডিকপল করা হয়।

এই API-এর মূল অংশটি WindowInfoTracker ইন্টারফেসে রয়েছে, যা একটি স্ট্যাটিক পদ্ধতিতে তৈরি করা হয়েছে যার জন্য একটি Activity প্রয়োজন:

step1/CameraCodelabDependencies.kt

@Provides
fun provideWindowInfoTracker(activity: Activity) =
        WindowInfoTracker.getOrCreate(activity)

আপনাকে এই কোডটি লিখতে হবে না কারণ এটি ইতিমধ্যেই রয়েছে, তবে WindowInfoTracker কীভাবে তৈরি করা হয়েছে তা বোঝার জন্য এটি দরকারী।

  1. যে কোনো উইন্ডো পরিবর্তন শুনতে, আপনার Activity onResume() পদ্ধতিতে এই পরিবর্তনগুলি শুনুন:

step1/MainActivity.kt

lifecycleScope.launch {
    foldingStateActor.checkFoldingState(
         this@MainActivity, 
         binding.viewFinder
    )
}
  1. এখন, FoldingStateActor ফাইলটি খুলুন, কারণ এটি checkFoldingState() পদ্ধতিটি পূরণ করার সময়।

আপনি ইতিমধ্যেই দেখেছেন, এটি আপনার Activity RESUMED পর্বে চলে এবং যেকোনো বিন্যাস পরিবর্তন শোনার জন্য এটি WindowInfoTracker ব্যবহার করে।

step1/FoldingStateActor.kt

windowInfoTracker.windowLayoutInfo(activity)
      .collect { newLayoutInfo ->
         activeWindowLayoutInfo = newLayoutInfo
         updateLayoutByFoldingState(cameraViewfinder)
      }

WindowInfoTracker ইন্টারফেস ব্যবহার করে, আপনি WindowLayoutInfo এর একটি Flow সংগ্রহ করতে windowLayoutInfo() কল করতে পারেন যাতে DisplayFeature এ সমস্ত উপলব্ধ তথ্য রয়েছে।

শেষ ধাপ হল এই পরিবর্তনগুলিতে প্রতিক্রিয়া জানানো এবং সেই অনুযায়ী বিষয়বস্তু সরানো। আপনি updateLayoutByFoldingState() পদ্ধতির মধ্যে এটি করেন, এক সময়ে এক ধাপ।

  1. activityLayoutInfo এ কিছু DisplayFeature বৈশিষ্ট্য রয়েছে তা নিশ্চিত করুন এবং তাদের মধ্যে অন্তত একটি হল FoldingFeature , অন্যথায় আপনি কিছু করতে চান না:

step1/FoldingStateActor.kt

val foldingFeature = activeWindowLayoutInfo?.displayFeatures
            ?.firstOrNull { it is FoldingFeature } as FoldingFeature?
            ?: return
  1. ডিভাইসের অবস্থান আপনার লেআউটকে প্রভাবিত করছে এবং আপনার অনুক্রমের সীমার বাইরে নয় তা নিশ্চিত করার জন্য ভাঁজের অবস্থান গণনা করুন:

step1/FoldingStateActor.kt

val foldPosition = FoldableUtils.getFeaturePositionInViewRect(
            foldingFeature,
            cameraViewfinder.parent as View
        ) ?: return

এখন, আপনি নিশ্চিত যে আপনার কাছে একটি FoldingFeature আছে যা আপনার লেআউটকে প্রভাবিত করে, তাই আপনাকে আপনার সামগ্রী সরাতে হবে।

  1. FoldingFeature HALF_OPEN কিনা চেক করুন অন্যথায় আপনি আপনার সামগ্রীর অবস্থান পুনরুদ্ধার করবেন। যদি এটি HALF_OPEN হয়, তাহলে আপনাকে আরেকটি চেক চালাতে হবে এবং ভাঁজের অভিযোজনের উপর ভিত্তি করে ভিন্নভাবে কাজ করতে হবে:

step1/FoldingStateActor.kt

if (foldingFeature.state == FoldingFeature.State.HALF_OPENED) {
    when (foldingFeature.orientation) {
        FoldingFeature.Orientation.VERTICAL -> {
            cameraViewfinder.moveToRightOf(foldPosition)
        }
        FoldingFeature.Orientation.HORIZONTAL -> {
            cameraViewfinder.moveToTopOf(foldPosition)
        }
    }
} else {
    cameraViewfinder.restore()
}

ভাঁজটি VERTICAL হলে, আপনি আপনার সামগ্রীটি ডানদিকে সরান, অন্যথায় আপনি এটিকে ভাঁজ অবস্থানের উপরে সরান৷

  1. আপনার অ্যাপ তৈরি করুন এবং চালান, এবং তারপরে আপনার ডিভাইসটি উন্মোচন করুন এবং সেই অনুযায়ী সামগ্রী সরানো দেখতে এটিকে ট্যাবলেটপ মোডে রাখুন!

7. অভিনন্দন!

এই কোডল্যাবে আপনি এমন কিছু ক্ষমতা সম্পর্কে শিখেছেন যা ভাঁজযোগ্য ডিভাইসগুলির জন্য অনন্য, যেমন রিয়ার ডিসপ্লে মোড বা ট্যাবলেটপ মোড এবং জেটপ্যাক উইন্ডো ম্যানেজার ব্যবহার করে কীভাবে সেগুলি আনলক করা যায়।

আপনি আপনার ক্যামেরা অ্যাপের জন্য দুর্দান্ত ব্যবহারকারীর অভিজ্ঞতা বাস্তবায়নের জন্য প্রস্তুত।

আরও পড়া

রেফারেন্স