Android N এবং তার আগের ভার্সনে সাজেশন

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

মনে রাখবেন: Android 7.1 (API লেভেল ২৫) পর্যন্ত এবং এর মধ্যে থাকা Android ভার্সনে চলা অ্যাপে সাজেশন দেওয়ার জন্য এখানে বর্ণিত API ব্যবহার করুন। Android 8.0 (API লেভেল ২৬) এবং তার পরবর্তী ভার্সনে চলা অ্যাপের জন্য সাজেশন প্রদান করতে, আপনার অ্যাপকে অবশ্যই সাজেশন চ্যানেল ব্যবহার করতে হবে।

Android ফ্রেমওয়ার্ক হোম স্ক্রিনে সাজেশনের সারি প্রদান করে ন্যূনতম-ইনপুট ইন্টার‍্যাকশনে সাহায্য করে। ডিভাইস প্রথমবার ব্যবহার করার পরে, কন্টেন্ট সাজেশন টিভি হোম স্ক্রিনের প্রথম সারিতে দেখা যায়। আপনার অ্যাপের কন্টেন্ট ক্যাটালগ থেকে সাজেশন কন্ট্রিবিউট করলে, ব্যবহারকারীদের আপনার অ্যাপে ফিরিয়ে আনতে সাহায্য করতে পারে।

Android TV-র হোম স্ক্রিনে সাজেশনের সারির উদাহরণ
ছবি ১. সাজেশনের সারির একটি উদাহরণ।

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

সাজেশনের জন্য পেশাদার পদ্ধতি

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

সাজেশনের ধরন

সাজেশন তৈরি করার সময়, ব্যবহারকারীদের অসম্পূর্ণ দেখার অ্যাক্টিভিটিতে ফিরিয়ে নিয়ে যাওয়ার জন্য লিঙ্ক করা উচিত অথবা এমন অ্যাক্টিভিটির সাজেশন দেওয়া উচিত যা সম্পর্কিত কন্টেন্ট পর্যন্ত বিস্তৃত। এখানে কিছু নির্দিষ্ট ধরনের সাজেশন দেওয়া হল যা আপনার বিবেচনা করা উচিত:

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

ব্যবহারকারীকে সেরা অভিজ্ঞতা প্রদান করার জন্য কীভাবে সাজেশন কার্ড ডিজাইন করবেন সেই সম্পর্কে আরও জানতে, Android TV ডিজাইন স্পেসিফিকেশনে সাজেশন রো দেখুন।

সাজেশনগুলি রিফ্রেশ করুন

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

সাজেশন কাস্টমাইজ করুন

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

গ্রুপ সংক্রান্ত সাজেশন

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

সাজেশনের সারি তৈরি বা আপডেট করার সময় সিস্টেম প্রতিটি গ্রুপের জন্য আলাদাভাবে সাজেশনের র‍্যাঙ্ক ও ক্রম নির্ধারণ করে। আপনার সাজেশনের জন্য গ্রুপ সংক্রান্ত তথ্য প্রদান করে, আপনি নিশ্চিত করতে পারেন যে আপনার সাজেশনগুলি যেন সম্পর্কহীন সাজেশনের অধীনে অর্ডার না করা হয়।

কোনও সাজেশনের গ্রুপ কী স্ট্রিং সেট করতে NotificationCompat.Builder.setGroup() ব্যবহার করুন। যেমন, নতুন ট্রেন্ডিং কন্টেন্ট আছে এমন গ্রুপের অন্তর্গত হিসেবে কোনও সাজেশনকে চিহ্নিত করতে, আপনি setGroup("trending") কল করতে পারেন।

সাজেশন পরিষেবা তৈরি করা

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

আপনার অ্যাপ্লিকেশনের জন্য সাজেশন পরিষেবা তৈরি করতে কীভাবে IntentService এক্সটেন্ড করতে হয় তা নিম্নলিখিত কোডের উদাহরণে দেখানো হয়েছে:

Kotlin

class UpdateRecommendationsService : IntentService("RecommendationService") {
    override protected fun onHandleIntent(intent: Intent) {
        Log.d(TAG, "Updating recommendation cards")
        val recommendations = VideoProvider.getMovieList()
        if (recommendations == null) return

        var count = 0

        try {
            val builder = RecommendationBuilder()
                    .setContext(applicationContext)
                    .setSmallIcon(R.drawable.videos_by_google_icon)

            for (entry in recommendations.entrySet()) {
                for (movie in entry.getValue()) {
                    Log.d(TAG, "Recommendation - " + movie.getTitle())

                    builder.setBackground(movie.getCardImageUrl())
                            .setId(count + 1)
                            .setPriority(MAX_RECOMMENDATIONS - count)
                            .setTitle(movie.getTitle())
                            .setDescription(getString(R.string.popular_header))
                            .setImage(movie.getCardImageUrl())
                            .setIntent(buildPendingIntent(movie))
                            .build()
                    if (++count >= MAX_RECOMMENDATIONS) {
                        break
                    }
                }
                if (++count >= MAX_RECOMMENDATIONS) {
                    break
                }
            }
        } catch (e: IOException) {
            Log.e(TAG, "Unable to update recommendation", e)
        }
    }

    private fun buildPendingIntent(movie: Movie): PendingIntent {
        val detailsIntent = Intent(this, DetailsActivity::class.java)
        detailsIntent.putExtra("Movie", movie)

        val stackBuilder = TaskStackBuilder.create(this)
        stackBuilder.addParentStack(DetailsActivity::class.java)
        stackBuilder.addNextIntent(detailsIntent)

        // Ensure a unique PendingIntents, otherwise all
        // recommendations end up with the same PendingIntent
        detailsIntent.setAction(movie.getId().toString())

        val intent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
        return intent
    }

    companion object {
        private val TAG = "UpdateRecommendationsService"
        private val MAX_RECOMMENDATIONS = 3
    }
}

জাভা

public class UpdateRecommendationsService extends IntentService {
    private static final String TAG = "UpdateRecommendationsService";
    private static final int MAX_RECOMMENDATIONS = 3;

    public UpdateRecommendationsService() {
        super("RecommendationService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d(TAG, "Updating recommendation cards");
        HashMap<String, List<Movie>> recommendations = VideoProvider.getMovieList();
        if (recommendations == null) return;

        int count = 0;

        try {
            RecommendationBuilder builder = new RecommendationBuilder()
                    .setContext(getApplicationContext())
                    .setSmallIcon(R.drawable.videos_by_google_icon);

            for (Map.Entry<String, List<Movie>> entry : recommendations.entrySet()) {
                for (Movie movie : entry.getValue()) {
                    Log.d(TAG, "Recommendation - " + movie.getTitle());

                    builder.setBackground(movie.getCardImageUrl())
                            .setId(count + 1)
                            .setPriority(MAX_RECOMMENDATIONS - count)
                            .setTitle(movie.getTitle())
                            .setDescription(getString(R.string.popular_header))
                            .setImage(movie.getCardImageUrl())
                            .setIntent(buildPendingIntent(movie))
                            .build();

                    if (++count >= MAX_RECOMMENDATIONS) {
                        break;
                    }
                }
                if (++count >= MAX_RECOMMENDATIONS) {
                    break;
                }
            }
        } catch (IOException e) {
            Log.e(TAG, "Unable to update recommendation", e);
        }
    }

    private PendingIntent buildPendingIntent(Movie movie) {
        Intent detailsIntent = new Intent(this, DetailsActivity.class);
        detailsIntent.putExtra("Movie", movie);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addParentStack(DetailsActivity.class);
        stackBuilder.addNextIntent(detailsIntent);
        // Ensure a unique PendingIntents, otherwise all
        // recommendations end up with the same PendingIntent
        detailsIntent.setAction(Long.toString(movie.getId()));

        PendingIntent intent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
        return intent;
    }
}

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

<manifest ... >
  <application ... >
    ...

    <service
            android:name="com.example.android.tvleanback.UpdateRecommendationsService"
            android:enabled="true" />
  </application>
</manifest>

সাজেশন তৈরি করুন

আপনার সাজেশন পরিষেবা চালু হয়ে গেলে, এটি অবশ্যই সাজেশন তৈরি করবে এবং Android ফ্রেমওয়ার্কে পাঠাবে। ফ্রেমওয়ার্ক Notification অবজেক্ট হিসেবে সাজেশন পায় যা নির্দিষ্ট টেমপ্লেট ব্যবহার করে এবং নির্দিষ্ট বিভাগ হিসেবে চিহ্নিত করা হয়।

ভ্যালু সেট করা হচ্ছে

সাজেশন কার্ডের জন্য UI এলিমেন্টের ভ্যালু সেট করতে, আপনি একটি বিল্ডার ক্লাস তৈরি করেন যা নিচে বর্ণিত বিল্ডার প্যাটার্ন অনুসরণ করে। প্রথমে, আপনি সাজেশন কার্ডের এলিমেন্টের ভ্যালু সেট করেন।

Kotlin

class RecommendationBuilder {
    ...

    fun setTitle(title: String): RecommendationBuilder {
        this.title = title
        return this
    }

    fun setDescription(description: String): RecommendationBuilder {
        this.description = description
        return this
    }

    fun setImage(uri: String): RecommendationBuilder {
        imageUri = uri
        return this
    }

    fun setBackground(uri: String): RecommendationBuilder {
        backgroundUri = uri
        return this
    }

...

জাভা

public class RecommendationBuilder {
    ...

    public RecommendationBuilder setTitle(String title) {
            this.title = title;
            return this;
        }

        public RecommendationBuilder setDescription(String description) {
            this.description = description;
            return this;
        }

        public RecommendationBuilder setImage(String uri) {
            imageUri = uri;
            return this;
        }

        public RecommendationBuilder setBackground(String uri) {
            backgroundUri = uri;
            return this;
        }
...

বিজ্ঞপ্তি তৈরি করুন

ভ্যালু সেট করা হয়ে গেলে, আপনি বিজ্ঞপ্তি তৈরি করেন, বিল্ডার ক্লাস থেকে বিজ্ঞপ্তিতে ভ্যালু অ্যাসাইন করেন এবং NotificationCompat.Builder.build() কল করেন।

এছাড়াও, setLocalOnly()-এ কল করতে ভুলবেন না যাতে NotificationCompat.BigPictureStyle বিজ্ঞপ্তি অন্য ডিভাইসে না দেখানো হয়।

নিম্নলিখিত কোডের উদাহরণ থেকে সাজেশন কীভাবে তৈরি করতে হয় তা দেখানো হয়েছে।

Kotlin

class RecommendationBuilder {
    ...

    @Throws(IOException::class)
    fun build(): Notification {
        ...

        val notification = NotificationCompat.BigPictureStyle(
        NotificationCompat.Builder(context)
                .setContentTitle(title)
                .setContentText(description)
                .setPriority(priority)
                .setLocalOnly(true)
                .setOngoing(true)
                .setColor(context.resources.getColor(R.color.fastlane_background))
                .setCategory(Notification.CATEGORY_RECOMMENDATION)
                .setLargeIcon(image)
                .setSmallIcon(smallIcon)
                .setContentIntent(intent)
                .setExtras(extras))
                .build()

        return notification
    }
}

জাভা

public class RecommendationBuilder {
    ...

    public Notification build() throws IOException {
        ...

        Notification notification = new NotificationCompat.BigPictureStyle(
                new NotificationCompat.Builder(context)
                        .setContentTitle(title)
                        .setContentText(description)
                        .setPriority(priority)
                        .setLocalOnly(true)
                        .setOngoing(true)
                        .setColor(context.getResources().getColor(R.color.fastlane_background))
                        .setCategory(Notification.CATEGORY_RECOMMENDATION)
                        .setLargeIcon(image)
                        .setSmallIcon(smallIcon)
                        .setContentIntent(intent)
                        .setExtras(extras))
                .build();

        return notification;
    }
}

সাজেশন পরিষেবা রান করুন

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

Kotlin

class BootupActivity : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d(TAG, "BootupActivity initiated")
        if (intent.action.endsWith(Intent.ACTION_BOOT_COMPLETED)) {
            scheduleRecommendationUpdate(context)
        }
    }

    private fun scheduleRecommendationUpdate(context: Context) {
        Log.d(TAG, "Scheduling recommendations update")
        val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val recommendationIntent = Intent(context, UpdateRecommendationsService::class.java)
        val alarmIntent = PendingIntent.getService(context, 0, recommendationIntent, 0)
        alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                INITIAL_DELAY,
                AlarmManager.INTERVAL_HALF_HOUR,
                alarmIntent
        )
    }

    companion object {
        private val TAG = "BootupActivity"
        private val INITIAL_DELAY:Long = 5000
    }
}

জাভা

public class BootupActivity extends BroadcastReceiver {
    private static final String TAG = "BootupActivity";

    private static final long INITIAL_DELAY = 5000;

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "BootupActivity initiated");
        if (intent.getAction().endsWith(Intent.ACTION_BOOT_COMPLETED)) {
            scheduleRecommendationUpdate(context);
        }
    }

    private void scheduleRecommendationUpdate(Context context) {
        Log.d(TAG, "Scheduling recommendations update");

        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent recommendationIntent = new Intent(context, UpdateRecommendationsService.class);
        PendingIntent alarmIntent = PendingIntent.getService(context, 0, recommendationIntent, 0);

        alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                INITIAL_DELAY,
                AlarmManager.INTERVAL_HALF_HOUR,
                alarmIntent);
    }
}

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

<manifest ... >
  <application ... >
    <receiver android:name="com.example.android.tvleanback.BootupActivity"
              android:enabled="true"
              android:exported="false">
      <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
      </intent-filter>
    </receiver>
  </application>
</manifest>

গুরুত্বপূর্ণ: বুট সম্পূর্ণ হওয়ার বিজ্ঞপ্তি পেতে হলে আপনার অ্যাপকে RECEIVE_BOOT_COMPLETED অনুমতির অনুরোধ করতে হবে। আরও তথ্যের জন্য, ACTION_BOOT_COMPLETED দেখুন।

আপনার সাজেশন পরিষেবা ক্লাসের onHandleIntent() মেথডে, ম্যানেজারের কাছে এইভাবে সাজেশন পোস্ট করুন:

Kotlin

val notification = notificationBuilder.build()
notificationManager.notify(id, notification)

জাভা

Notification notification = notificationBuilder.build();
notificationManager.notify(id, notification);