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

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

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

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

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

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

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

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

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

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

حالت صفحه نمایش دوتایی به شما امکان می دهد محتوا را در هر دو صفحه نمایشگر تاشو به طور همزمان نشان دهید. حالت صفحه نمایش دوگانه در 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 currently available to be enabled.
    }
    WindowAreaCapability.Status.WINDOW_AREA_STATUS_AVAILABLE -> {
      // The selected display mode is currently available to 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 currently available to be enabled.
}
else if (capabilityStatus.equals(WindowAreaCapability.Status.WINDOW_AREA_STATUS_AVAILABLE)) {
  // The selected display mode is currently available to 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, که اجرای آن ساده‌تر است، زیرا callback ارائه‌کننده‌ای را دریافت نمی‌کند که اجازه نمایش محتوا را در یک ناحیه پنجره می‌دهد، اما در عوض کل فعالیت را به ناحیه دیگری منتقل می‌کند:

کاتلین

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}");
    }
}

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

منابع اضافی

{% کلمه به کلمه %} {% آخر کلمه %} {% کلمه به کلمه %} {% آخر کلمه %}