پشتیبانی از حالت های نمایش تاشو

دستگاه های تاشو تجربه های منحصر به فردی از مشاهده را ارائه می دهند. حالت نمایش عقب و حالت دو صفحه نمایش به شما امکان می دهد ویژگی های نمایشگر ویژه ای را برای دستگاه های تاشو مانند پیش نمایش سلفی دوربین عقب و نمایشگرهای همزمان اما متفاوت در صفحه های داخلی و خارجی ایجاد کنید.

حالت نمایش عقب

معمولاً وقتی یک دستگاه تاشو باز می شود، فقط صفحه داخلی فعال است. حالت نمایش عقب به شما امکان می دهد یک فعالیت را به صفحه بیرونی یک دستگاه تاشو منتقل کنید، که معمولاً در حالی که دستگاه باز می شود، رو به دور از کاربر است. صفحه نمایش داخلی به طور خودکار خاموش می شود.

یک برنامه جدید این است که پیش‌نمایش دوربین را در صفحه بیرونی نمایش دهد، بنابراین کاربران می‌توانند با دوربین پشتی سلفی بگیرند، که معمولاً عملکرد عکس‌برداری بسیار بهتری نسبت به دوربین جلو ارائه می‌دهد.

برای فعال کردن حالت نمایش عقب، کاربران به یک گفتگو پاسخ می دهند تا به برنامه اجازه دهد صفحه نمایش را تغییر دهد، به عنوان مثال:

شکل 1. گفتگوی سیستم برای اجازه دادن به شروع حالت نمایش عقب.

سیستم دیالوگ را ایجاد می کند، بنابراین هیچ توسعه ای از طرف شما مورد نیاز نیست. بسته به وضعیت دستگاه، دیالوگ های مختلف ظاهر می شوند. به عنوان مثال، سیستم به کاربران دستور می دهد تا در صورت بسته بودن دستگاه، دستگاه را باز کنند. شما نمی توانید گفتگو را سفارشی کنید، و می تواند در دستگاه هایی از OEM های مختلف متفاوت باشد.

می‌توانید حالت نمایش عقب را با برنامه دوربین Pixel Fold امتحان کنید. یک نمونه پیاده‌سازی را در لبه کد مشاهده کنید. برنامه دوربین خود را در دستگاه‌های تاشو با Jetpack WindowManager بهینه کنید .

حالت دو صفحه نمایش

حالت دو صفحه نمایش به شما امکان می دهد محتوا را در هر دو صفحه نمایشگر تاشو به طور همزمان نشان دهید. حالت دو صفحه‌نمایش در Pixel Fold دارای Android 14 (سطح API 34) یا بالاتر در دسترس است.

یک مثال استفاده از مفسر دو صفحه است.

شکل 2. مفسر دو صفحه نمایش محتوای مختلف را در نمایشگرهای جلو و عقب نشان می دهد.

حالت ها را به صورت برنامه نویسی فعال کنید

از طریق APIهای Jetpack WindowManager ، از نسخه کتابخانه 1.2.0-beta03، می‌توانید به حالت نمایش عقب و حالت دو صفحه‌نمایش دسترسی داشته باشید.

وابستگی WindowManager را به فایل build.gradle ماژول برنامه خود اضافه کنید:

شیار

dependencies {
    implementation "androidx.window:window:1.2.0-beta03"
}

کاتلین

dependencies {
    implementation("androidx.window:window:1.2.0-beta03")
}

نقطه ورود WindowAreaController است که اطلاعات و رفتار مربوط به جابجایی پنجره ها بین نمایشگرها یا بین مناطق نمایشگر روی دستگاه را ارائه می دهد. WindowAreaController به شما امکان می دهد لیست اشیاء WindowAreaInfo موجود را جستجو کنید.

از WindowAreaInfo برای دسترسی به WindowAreaSession ، رابطی که یک ویژگی منطقه پنجره فعال را نشان می دهد، استفاده کنید. از WindowAreaSession برای تعیین در دسترس بودن یک WindowAreaCapability خاص استفاده کنید.

هر قابلیت مربوط به یک WindowAreaCapability.Operation خاص است. در نسخه 1.2.0-beta03، Jetpack WindowManager از دو نوع عملیات پشتیبانی می کند:

در اینجا مثالی از نحوه اعلام متغیرها برای حالت نمایش عقب و حالت دو صفحه نمایش در فعالیت اصلی برنامه آمده است:

کاتلین

private lateinit var windowAreaController: WindowAreaController
private lateinit var displayExecutor: Executor
private var windowAreaSession: WindowAreaSession? = null
private var windowAreaInfo: WindowAreaInfo? = null
private var capabilityStatus: WindowAreaCapability.Status =
    WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED

private val dualScreenOperation = WindowAreaCapability.Operation.OPERATION_PRESENT_ON_AREA
private val rearDisplayOperation = WindowAreaCapability.Operation.OPERATION_TRANSFER_ACTIVITY_TO_AREA

جاوا

private WindowAreaControllerCallbackAdapter windowAreaController = null;
private Executor displayExecutor = null;
private WindowAreaSessionPresenter windowAreaSession = null;
private WindowAreaInfo windowAreaInfo = null;
private WindowAreaCapability.Status capabilityStatus  =
        WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED;

private WindowAreaCapability.Operation dualScreenOperation =
        WindowAreaCapability.Operation.OPERATION_PRESENT_ON_AREA;
private WindowAreaCapability.Operation rearDisplayOperation =
        WindowAreaCapability.Operation.OPERATION_TRANSFER_ACTIVITY_TO_AREA;

در اینجا نحوه مقداردهی اولیه متغیرها در متد onCreate() فعالیت خود آورده شده است:

کاتلین

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 -> windowAreaInfo = info }
            .map { it?.getCapability(operation)?.status ?: WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED }
            .distinctUntilChanged()
            .collect {
                capabilityStatus = it
            }
    }
}

جاوا

displayExecutor = ContextCompat.getMainExecutor(this);
windowAreaController = new WindowAreaControllerCallbackAdapter(WindowAreaController.getOrCreate());
windowAreaController.addWindowAreaInfoListListener(displayExecutor, this);

windowAreaController.addWindowAreaInfoListListener(displayExecutor,
  windowAreaInfos -> {
    for(WindowAreaInfo newInfo : windowAreaInfos){
        if(newInfo.getType().equals(WindowAreaInfo.Type.TYPE_REAR_FACING)){
            windowAreaInfo = newInfo;
            capabilityStatus = newInfo.getCapability(presentOperation).getStatus();
            break;
        }
    }
});

قبل از شروع عملیات، در دسترس بودن قابلیت خاص را بررسی کنید:

کاتلین

when (capabilityStatus) {
    WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED -> {
      // The selected display mode is not supported on this device.
    }
    WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNAVAILABLE -> {
      // The selected display mode is not available.
    }
    WindowAreaCapability.Status.WINDOW_AREA_STATUS_AVAILABLE -> {
      // The selected display mode is available and can be enabled.
    }
    WindowAreaCapability.Status.WINDOW_AREA_STATUS_ACTIVE -> {
      // The selected display mode is already active.
    }
    else -> {
      // The selected display mode status is unknown.
    }
}

جاوا

if (capabilityStatus.equals(WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNSUPPORTED)) {
  // The selected display mode is not supported on this device.
}
else if (capabilityStatus.equals(WindowAreaCapability.Status.WINDOW_AREA_STATUS_UNAVAILABLE)) {
  // The selected display mode is not available.
}
else if (capabilityStatus.equals(WindowAreaCapability.Status.WINDOW_AREA_STATUS_AVAILABLE)) {
  // The selected display mode is available and can be enabled.
}
else if (capabilityStatus.equals(WindowAreaCapability.Status.WINDOW_AREA_STATUS_ACTIVE)) {
  // The selected display mode is already active.
}
else {
  // The selected display mode status is unknown.
}

حالت دو صفحه نمایش

مثال زیر اگر قابلیت از قبل فعال باشد جلسه را می بندد یا تابع presentContentOnWindowArea() را فراخوانی می کند:

کاتلین

fun toggleDualScreenMode() {
    if (windowAreaSession != null) {
        windowAreaSession?.close()
    }
    else {
        windowAreaInfo?.token?.let { token ->
            windowAreaController.presentContentOnWindowArea(
                token = token,
                activity = this,
                executor = displayExecutor,
                windowAreaPresentationSessionCallback = this
            )
        }
    }
}

جاوا

private void toggleDualScreenMode() {
    if(windowAreaSession != null) {
        windowAreaSession.close();
    }
    else {
        Binder token = windowAreaInfo.getToken();
        windowAreaController.presentContentOnWindowArea( token, this, displayExecutor, this);
    }
}

به استفاده از فعالیت اصلی برنامه به عنوان آرگومان WindowAreaPresentationSessionCallback توجه کنید.

API از یک رویکرد شنونده استفاده می کند: وقتی درخواستی برای ارائه محتوا به نمایشگر دیگر یک تاشو ارائه می کنید، جلسه ای را آغاز می کنید که از طریق متد onSessionStarted() شنونده برگردانده می شود. وقتی جلسه را می بندید، در متد onSessionEnded() تاییدیه دریافت می کنید.

برای ایجاد شنونده، رابط WindowAreaPresentationSessionCallback را پیاده سازی کنید:

کاتلین

class MainActivity : AppCompatActivity(), windowAreaPresentationSessionCallback

جاوا

public class MainActivity extends AppCompatActivity implements WindowAreaPresentationSessionCallback

شنونده باید متدهای onSessionStarted() ، onSessionEnded(), و onContainerVisibilityChanged() را پیاده سازی کند. روش‌های پاسخ به تماس شما را از وضعیت جلسه مطلع می‌کنند و به شما امکان می‌دهند برنامه را مطابق با آن به‌روزرسانی کنید.

پاسخ به تماس onSessionStarted() یک WindowAreaSessionPresenter به عنوان آرگومان دریافت می کند. آرگومان ظرفی است که به شما امکان می دهد به یک ناحیه پنجره دسترسی داشته باشید و محتوا را نشان دهید. هنگامی که کاربر پنجره برنامه اصلی را ترک می کند، ارائه می تواند به طور خودکار توسط سیستم رد شود، یا ارائه می تواند با فراخوانی WindowAreaSessionPresenter#close() بسته شود.

برای سایر فراخوان‌ها، برای سادگی، کافی است در بدنه تابع برای هر گونه خطا بررسی کنید و وضعیت را ثبت کنید:

کاتلین

override fun onSessionStarted(session: WindowAreaSessionPresenter) {
    windowAreaSession = session
    val view = TextView(session.context)
    view.text = "Hello world!"
    session.setContentView(view)
}

override fun onSessionEnded(t: Throwable?) {
    if(t != null) {
        Log.e(logTag, "Something was broken: ${t.message}")
    }
}

override fun onContainerVisibilityChanged(isVisible: Boolean) {
    Log.d(logTag, "onContainerVisibilityChanged. isVisible = $isVisible")
}

جاوا

@Override
public void onSessionStarted(@NonNull WindowAreaSessionPresenter session) {
    windowAreaSession = session;
    TextView view = new TextView(session.getContext());
    view.setText("Hello world, from the other screen!");
    session.setContentView(view);
}

@Override public void onSessionEnded(@Nullable Throwable t) {
    if(t != null) {
        Log.e(logTag, "Something was broken: ${t.message}");
    }
}

@Override public void onContainerVisibilityChanged(boolean isVisible) {
    Log.d(logTag, "onContainerVisibilityChanged. isVisible = " + isVisible);
}

برای حفظ ثبات در سراسر اکوسیستم، از نماد رسمی Dual Screen برای نشان دادن نحوه فعال یا غیرفعال کردن حالت دو صفحه نمایش به کاربران استفاده کنید.

برای نمونه کار، DualScreenActivity.kt را ببینید.

حالت نمایش عقب

مشابه مثال حالت دو صفحه‌نمایش، مثال زیر از یک تابع toggleRearDisplayMode() جلسه را می‌بندد، اگر قابلیت قبلاً فعال باشد، یا تابع transferActivityToWindowArea() را فراخوانی می‌کند:

کاتلین

fun toggleRearDisplayMode() {
    if(capabilityStatus == WindowAreaCapability.Status.WINDOW_AREA_STATUS_ACTIVE) {
        if(windowAreaSession == null) {
            windowAreaSession = windowAreaInfo?.getActiveSession(
                operation
            )
        }
        windowAreaSession?.close()
    } else {
        windowAreaInfo?.token?.let { token ->
            windowAreaController.transferActivityToWindowArea(
                token = token,
                activity = this,
                executor = displayExecutor,
                windowAreaSessionCallback = this
            )
        }
    }
}

جاوا

void toggleDualScreenMode() {
    if(capabilityStatus == WindowAreaCapability.Status.WINDOW_AREA_STATUS_ACTIVE) {
        if(windowAreaSession == null) {
            windowAreaSession = windowAreaInfo.getActiveSession(
                operation
            )
        }
        windowAreaSession.close()
    }
    else {
        Binder token = windowAreaInfo.getToken();
        windowAreaController.transferActivityToWindowArea(token, this, displayExecutor, this);
    }
}

در این مورد، فعالیت نمایش داده شده به عنوان یک WindowAreaSessionCallback استفاده می‌شود، که اجرای آن ساده‌تر است، زیرا پاسخ به تماس ارائه‌کننده‌ای را دریافت نمی‌کند که اجازه نمایش محتوا در یک ناحیه پنجره را می‌دهد، اما در عوض کل فعالیت را به ناحیه دیگری منتقل می‌کند:

کاتلین

override fun onSessionStarted() {
    Log.d(logTag, "onSessionStarted")
}

override fun onSessionEnded(t: Throwable?) {
    if(t != null) {
        Log.e(logTag, "Something was broken: ${t.message}")
    }
}

جاوا

@Override public void onSessionStarted(){
    Log.d(logTag, "onSessionStarted");
}

@Override public void onSessionEnded(@Nullable Throwable t) {
    if(t != null) {
        Log.e(logTag, "Something was broken: ${t.message}");
    }
}

برای حفظ ثبات در سراسر اکوسیستم، از نماد رسمی دوربین عقب استفاده کنید تا به کاربران نشان دهید چگونه حالت نمایش عقب را فعال یا غیرفعال کنند.

منابع اضافی