เมื่อวันก่อนแอบไปส่องฟีเจอร์ใหม่ๆใน Android 7.0 Nougat ดูก็พบว่ามีฟีเจอร์ตัวหนึ่งที่น่าสนใจที่มีชื่อว่า Quick Settings Tile ก็เลยหยิบมาเล่าให้ฟังเล่นๆซะหน่อย

Quick Settings Tile

Quick Settings นั้นเป็นฟีเจอร์ที่เพิ่มความสามารถให้กับ Notification Shade หรือแถบ Notification ซึ่งผู้ใช้ส่วนใหญ่ได้สัมผัสกันมาตั้งแต่สมัย Android 5.0 Lollipop แล้วล่ะ

และในที่สุดก็เปิดให้นักพัฒนาสามารถ Custom เจ้า Quick Settings Tile ได้แล้ว เย้! โดยมีชื่อเรียกว่า Quick Settings Tile API นั่นเอง

แล้ว… มันใช้งานยังไงล่ะ?

Quick Settings จะทำงานในรูปแบบของ Service โดยที่ Quick Settings นั้นจะมีคลาสที่ชื่อว่า TileService ให้ใช้งาน แบบนี้

// AwesomeTileService.kt
class AwesomeTileService: TileService() { 
    /* ... */
}

และเวลาประกาศ Service ไว้ใน Android Manifest จะบังคับให้ประกาศ Permission สำหรับ Quick Settings ดังนี้

android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"

การที่ระบบแอนดรอยด์จะรู้ได้ว่า Service ตัวนี้มีไว้แสดงใน Quick Settings Tile ก็จะมาจากการกำหนดค่าไว้ใน Intent Filter แบบนี้

และสิ่งสุดท้ายใน Android Manifest ให้กำหนด android:icon กับ android:label ด้วย เพราะทั้งสองค่านี้จะถูกดึงไปแสดงเป็น Quick Settings นั่นเอง ดังนั้น Service ที่ประกาศไว้ใน Android Manifest จะเป็นแบบนี้

<!-- AndroidManifest.xml -->
<?xml version="1.0" encoding="utf-8"?>
<manifest>
    <application>
        <!-- ... -->
        <service
            android:icon="@drawable/ic_profile"
            android:label="@string/qs_tile_name"
            android:name=".AwesomeTileService"
            android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
            <intent-filter>
                <action android:name="android.service.quicksettings.action.QS_TILE" />
            </intent-filter>
        </service>
    </application>
</manifest>

จากนั้นให้ลองทดสอบดูก่อนนะว่าทำงานได้หรือไม่

สำหรับไอคอนที่สร้างขึ้นมาแสดงใน Quick Settings นี้จะขอเรียกว่า Tile นะ

มาดูกันต่อว่าทำอะไรกับ Quick Settings Tile ได้บ้าง

สำหรับ Public Method ที่มีให้ Override จะมีดังนี้

// QuickSettingService.kt
class QuickSettingService: TileService() { 
    override fun onTileAdded() {
        /* ... */
    }
    
    override fun onTileRemoved() {
        /* ... */
    }
    
    override fun onStartListening() {
        /* ... */
    }
    
    override fun onStopListening() {
        /* .... */
    }
    
    override fun onClick() {
        /* ... */
    }
}
  • onTileAdded : ทำงานก็ต่อเมื่อ Quick Settings ถูกเพิ่มเข้าไปใน Quick Settings Tile
  • onTileRemoved : ทำงานก็ต่อเมื่อ Quick Settings ถูกถอดออกจาก Quick Settings Tile
  • onStartListener : ทำงานก็ต่อเมื่อ Tile อยู่ในสถานะ Listening
  • onStopListener : ทำงานก็ต่อเมื่อ Tile ไม่ได้อยู่ในสถานะ Listening
  • onClick : ทำงานก็ต่อเมื่อผู้ใช้มีการกดเลือกที่ Tile ตัวนั้นๆ

และ Public Method ที่มีให้เรียกใช้งาน (Override ไม่ได้) จะมีดังนี้

fun getQsTile(): Tile
fun isLocked(): Boolean
fun isSecure(): Boolean
fun requestListeningState(context: Context, compnent: ComponentName)
fun showDialog(dialog: Dialog)
fun startActivityAndCollapse(intent: Intent)
fun unlockAndRun(runnable: Runnable)
  • getQsTile : ดึงคลาส Tile เพื่อใช้ในการอ่าน/กำหนดค่าให้กับ Tile
  • isLocked : เช็คว่าอยู่ใน Lock Screen (เพราะ Quick Settings Tile สามารถแสดงในหน้า Lock Screen ได้)
  • isSecure : เช็คว่าเครื่องนั้นๆกำหนด Lock Screen เป็นแบบ Secure หรือไม่ (Pattern, Password และอื่นๆ ที่ไม่ใช่ None หรือ Swipe)
  • requestListeningState : เป็นการเรียก Listening State ของ Tile เพื่ออัพเดท
  • showDialog : แสดง Dialog พร้อมกับปิดหน้าต่าง Notification Shade ลง
  • startActivityAndCollapse : เปิด Activity พร้อมกับปิดหน้าต่าง Notification Shade ลง
  • unlockAndRun : ปลดล็อคหน้าจอและทำคำสั่งที่กำหนดไว้ใน Runnable

การทำงานของ Listening State

Tile นั้นจะมี Listening State อยู่ 2 State ด้วยกันคือ Start กับ Stop เพื่อให้สามารถอัพเดทสถานะของตัว Tile ได้

โดยปกติแล้ว Listening จะเริ่มทำงาน (Start) เมื่อ Tile ถูกแสดงให้เห็น แม้ว่าจะแค่เปิดหน้าต่าง Quick Settings Tile ก็ตาม และก็จะหยุดทำงาน (Stop) เมื่อ Tile ไม่แสดงให้ผู้ใช้เห็นแล้ว

นอกจากนี้ยังกำหนดให้ Listening ทำงานในแบบ Active Mode ได้อีกด้วย โดยกำหนดใน Android Manifest ด้วย <meta-data> แบบนี้

<meta-data 
    android:name="android.service.quicksettings.ACTIVE_TILE" 
    android:value="true" />
<service 
    android:name=".AwesomeTileService"
    android:icon="@drawable/ic_profile"
    android:label="@string/qs_tile_name" 
    android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"> 
        <intent-filter> 
            <action 
                android:name="android.service.quicksettings.action.QS_TILE" />
        </intent-filter>
        <meta-data 
            android:name="android.service.quicksettings.ACTIVE_TILE" 
            android:value="true" />
</service>

เมื่ออยู่ใน Active Mode จะทำให้ Listening State เปลี่ยนไป โดยที่ Start จะไม่ทำงานในทันทีที่ Tile ถูกแสดงให้ผู้ใช้เห็น แต่ว่าจะทำงานก็ต่อเมื่อใช้คำสั่ง requestListeningState เท่านั้น

val context: Contetx = /* ... */
val serviceClassName: Class<?> = /* ... */
val component = Component(context, serviceClassName)
requestListeningState(context, component)

แต่ว่า Listening ก็หยุดทำงานเมื่อ Tile หายไปจากหน้าจอเหมือนเดิมอยู่นะ

และถ้าไม่ได้ประกาศ <meta-data> ดังกล่าวก็จะทำให้คำสั่ง requestListeningState ไม่มีผลใดๆ

การทำงานของ Unlock And Run

อย่างที่บอกในตอนแรกว่า Quick Settings Tile นั้นสามารถแสดงในระหว่างอยู่หน้าจอ Lock Screen ได้ ดังนั้นจึงสามารถสั่งให้ Unlock หน้าจอได้

แต่ทว่า Lock Screen ก็สามารถมีการใส่รหัสเพื่อปลดล็อคหน้าจอได้ ดังนั้นคำสั่ง unlockAndRun จะยังไม่ทำงานในทันที เพื่อรอให้ผู้ใช้ปลดล็อคหน้าจอเสร็จเสียก่อน และถ้าผู้ใช้ไม่ยอมปลดล็อคหน้าจอก็จะไม่ทำคำสั่งนั้นเช่นกัน

// AwesomeTileService.kt
class AwesomeTileService: TimeService() {
    private val runnable = Runnable {
        // Do something
    }

    override fun onClick() {
        unlockAndRun(runnable)
    }
}

ดังนั้นคำสั่ง unlockAndRun จึงต้องใช้ Runnable เพื่อกำหนดคำสั่งที่จะให้ทำงานหลังจากปลดล็อคหน้าจอแล้วนั่นเอง

คำสั่งต่างๆของ Tile

สำหรับการกำหนดรูปแบบการแสดงผลของ Tile นั้นจะไม่ได้อยู่ในคลาส TileService โดยตรง แต่จะมีคลาส Tile สำหรับกำหนดอีกทีหนึ่ง ซึ่ง Tile สามารถดึงได้จากคำสั่ง getQsTile

val tile: Tile = getQsTile()

และคำสั่งที่มีให้ใช้งานใน Tile จะมีดังนี้

fun setIcon(icon: Icon)
fun setLabel(label: CharSequence)
fun setState(state: Int)
fun setContentDescription(contentDescription: CharSequence)
fun updateTile()
fun getIcon(): Icon
fun getState(): Int
fun getLabel(): CharSequnce
fun getContentDescription(): CharSequence
  • setIcon : กำหนดภาพที่จะใช้แสดงใน Tile
  • setLabel : กำหนดข้อความที่จะใช้แสดงใน Tile
  • setState : กำหนดสถานะของ Tile
  • setContentDescription : กำหนด Content Description ของ Tile
  • updateTile : อัพเดทค่าทั้งหมดของ Tile
  • getIcon : ดึงภาพที่ใช้แสดงใน Tile
  • getState : ดึงสถานะของ Tile
  • getLabel : ดึงข้อความที่ใช้แสดงใน Tile
  • getContentDescription : ดึง Content Description ของ Tile

การกำหนดค่าต่างๆให้กับ Tile

สำหรับการกำหนด Label ให้กับ Tile ก็เป็นแค่ CharSequence ธรรมดาๆไม่มีอะไรซับซ้อน

สำหรับการกำหนดค่า Icon จะต้องกำหนดค่าด้วยคลาส Icon แบบนี้

val icon: Icon = Icon.createWithResource(/* ... */)
getQsTile().apply {
    setIcon(icon)
}

โดยที่คลาส Icon สามารถดึงภาพได้หลายๆรูปแบบไม่ว่าจะเป็น Drawable, Bitmap, Uri, File หรือแม้แต่ Byte Array ก็ตาม

แต่ภาพที่ใช้ใน Tile จะถูกทำให้เป็นสีขาวทั้งหมด ดังนั้นเลี่ยงการใช้ภาพที่เป็นหลากสี ควรใช้ภาพที่เป็นแบบไอคอนแทน (พื้นหลังโปร่งใส และเป็นสีโทนเดียว)

สำหรับการกำหนดสถานะของ Tile จะมีอยู่ด้วยกัน 3 สถานะดังนี้

Tile.STATE_ACTIVE
Tile.STATE_INACTIVE
Tile.STATE_UNAVAILABLE
  • Active เป็นสถานะที่บ่งบอกว่า Tile กำลังทำงานอยู่ (Active)
  • Inactive เป็นสถานะที่บ่งบอกว่า Tile ไม่ได้ทำงาน (Inactive)
  • Unavailable เป็นสถานะที่บ่งบอกว่า Tile ไม่สามารถใช้งานหรือทำงานได้

สำหรับสถานะ Active และ Inactive ผู้ใช้สามารถกดแล้วเข้า Event ที่ชื่อว่า onClick ได้ แต่สำหรับกรณีของสถานะ Unavailable จะไม่เกิดอะไรขึ้น จึงมีไว้สำหรับกำหนดเมื่อบางอย่างไม่สามารถทำงานได้เลย (เช่น Tile สำหรับสถานะ Bluetooth แต่ทว่าเครื่องนั้นไม่มี Bluetooth จึงไม่สามารถใช้งาน Tile ตัวนี้ได้)

และเมื่อกำหนดค่าต่างๆ จะยังไม่มีผลทันที จนกว่าจะเรียกคำสั่ง updateTile

getQsTile().apply {
    setState(Tile.STATE_INACTIVE)
    setLabel(getString(/* ... */))
    setState(Tile.STATE_ACTIVE)
    updateTile()
}

การประยุกต์ใช้งาน

สุดท้ายนี้ก็ขึ้นอยู่กับว่าจะเอาไปประยุกต์ใช้งานกับแอปฯต่างๆยังไงแล้วล่ะ เพราะการเปิด Quick Settings Tile API นั้นจะช่วยเพิ่มความสามารถของแอปฯได้หรือไม่ก็ขึ้นอยู่กับว่าแอปฯตัวนั้นๆเป็นแบบไหน ในกรณีที่เป็นแอพที่เป็นแอปฯที่ต้องใช้การบ่อยๆ มีการเปิด/ปิดการทำงานบางอย่างของแอปฯอยู่เป็นประจำ ก็จะเหมาะมากๆที่ทำ Quick Settings Tile เพื่อให้ผู้ใช้งานสามารถใช้งานได้สะดวกยิ่งขึ้น

แหล่งข้อมูลอ้างอิง