Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8940331 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 9311025 from 41c5f1d9 to tm-qpr2-release

Change-Id: I042fe088350e2816a9fefbe56b18af9da3bbbe86
parents c718dfe9 41c5f1d9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
    <uses-permission android:name="android.permission.SET_WALLPAPER_COMPONENT" />
    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
    <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE" />
    <uses-permission android:name="android.permission.ACCESS_KEYGUARD_QUICK_AFFORDANCES" />

    <queries>
        <!-- Specific intents Wallpaper picker query for -->
+99 −0
Original line number Diff line number Diff line
package com.android.customization.picker.clock

import android.os.Handler
import android.os.UserHandle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.plugins.ClockId
import com.android.systemui.plugins.ClockMetadata
import com.android.systemui.plugins.ClockProviderPlugin
import com.android.systemui.plugins.PluginManager
import com.android.systemui.shared.clocks.ClockRegistry
import com.android.systemui.shared.clocks.DefaultClockProvider
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config

/** Tests of [ClockCustomDemoFragment]. */
@RunWith(RobolectricTestRunner::class)
@Config(manifest = Config.NONE)
class ClockCustomDemoFragmentTest {
    private lateinit var mActivity: AppCompatActivity
    private var mClockCustomDemoFragment: ClockCustomDemoFragment? = null
    private lateinit var registry: ClockRegistry
    @Mock private lateinit var mockPluginManager: PluginManager
    @Mock private lateinit var mockHandler: Handler
    @Mock private lateinit var fakePlugin: ClockProviderPlugin
    @Mock private lateinit var defaultClockProvider: DefaultClockProvider

    private var settingValue: String = ""

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        mActivity = Robolectric.buildActivity(AppCompatActivity::class.java).get()
        mClockCustomDemoFragment = ClockCustomDemoFragment()
        Mockito.`when`(defaultClockProvider.getClocks())
            .thenReturn(listOf(ClockMetadata("DEFAULT", "Default Clock")))
        registry =
            object :
                ClockRegistry(
                    mActivity,
                    mockPluginManager,
                    mockHandler,
                    isEnabled = true,
                    userHandle = UserHandle.USER_ALL,
                    defaultClockProvider = defaultClockProvider
                ) {
                override var currentClockId: ClockId
                    get() = settingValue
                    set(value) {
                        settingValue = value
                    }

                override fun getClocks(): List<ClockMetadata> {
                    return defaultClockProvider.getClocks() +
                        listOf(
                            ClockMetadata("CLOCK_1", "Clock 1"),
                            ClockMetadata("CLOCK_2", "Clock 2"),
                            ClockMetadata("CLOCK_NOT_IN_USE", "Clock not in use")
                        )
                }
            }

        mClockCustomDemoFragment!!.clockRegistry = registry
        mClockCustomDemoFragment!!.recyclerView = RecyclerView(mActivity)
        mClockCustomDemoFragment!!.recyclerView.layoutManager =
            LinearLayoutManager(mActivity, RecyclerView.VERTICAL, false)
        mClockCustomDemoFragment!!.pluginListener.onPluginConnected(fakePlugin, mActivity)
    }

    @Test
    fun testItemCount_getCorrectClockCount() {
        Assert.assertEquals(3, mClockCustomDemoFragment!!.recyclerView.adapter!!.itemCount)
    }

    @Test
    fun testClick_setCorrectClockId() {
        mClockCustomDemoFragment!!
            .recyclerView
            .measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
        mClockCustomDemoFragment!!.recyclerView.layout(0, 0, 100, 10000)
        val testPosition = 1
        mClockCustomDemoFragment!!
            .recyclerView
            .findViewHolderForAdapterPosition(testPosition)
            ?.itemView
            ?.performClick()
        Assert.assertEquals("CLOCK_1", settingValue)
    }
}
+3 −2
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ import android.view.LayoutInflater;

import androidx.annotation.Nullable;

import com.android.customization.picker.clock.ClockCustomFragment;
import com.android.customization.picker.clock.ClockCustomDemoFragment;
import com.android.customization.picker.clock.ClockSectionView;
import com.android.wallpaper.R;
import com.android.wallpaper.config.Flags;
@@ -45,7 +45,8 @@ public class ClockSectionController implements CustomizationSectionController<Cl
        ClockSectionView view = (ClockSectionView) LayoutInflater.from(context).inflate(
                R.layout.clock_section_view,
                null);
        view.setOnClickListener(v -> mNavigationController.navigateTo(new ClockCustomFragment()));
        view.setOnClickListener(v ->
                mNavigationController.navigateTo(new ClockCustomDemoFragment()));
        return view;
    }
}
+191 −0
Original line number Diff line number Diff line
package com.android.customization.picker.clock

import android.app.NotificationManager
import android.content.ComponentName
import android.content.Context
import android.os.Bundle
import android.os.Handler
import android.os.UserHandle
import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.FrameLayout
import android.widget.TextView
import androidx.core.view.setPadding
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.plugins.ClockMetadata
import com.android.systemui.plugins.ClockProviderPlugin
import com.android.systemui.plugins.Plugin
import com.android.systemui.plugins.PluginListener
import com.android.systemui.plugins.PluginManager
import com.android.systemui.shared.clocks.ClockRegistry
import com.android.systemui.shared.clocks.DefaultClockProvider
import com.android.systemui.shared.plugins.PluginActionManager
import com.android.systemui.shared.plugins.PluginEnabler
import com.android.systemui.shared.plugins.PluginEnabler.ENABLED
import com.android.systemui.shared.plugins.PluginInstance
import com.android.systemui.shared.plugins.PluginManagerImpl
import com.android.systemui.shared.plugins.PluginPrefs
import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager_Factory
import com.android.wallpaper.R
import com.android.wallpaper.picker.AppbarFragment
import java.util.concurrent.Executors

private val TAG = ClockCustomDemoFragment::class.simpleName

class ClockCustomDemoFragment : AppbarFragment() {
    @VisibleForTesting lateinit var clockRegistry: ClockRegistry
    val isDebugDevice = true
    val privilegedPlugins = listOf<String>()
    val action = ClockProviderPlugin.ACTION
    lateinit var view: ViewGroup
    @VisibleForTesting lateinit var recyclerView: RecyclerView
    lateinit var pluginManager: PluginManager
    @VisibleForTesting
    val pluginListener =
        object : PluginListener<ClockProviderPlugin> {
            override fun onPluginConnected(plugin: ClockProviderPlugin, context: Context) {
                val listInUse = clockRegistry.getClocks().filter { "NOT_IN_USE" !in it.clockId }
                recyclerView.adapter = ClockRecyclerAdapter(listInUse, context, clockRegistry)
            }
        }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        val defaultClockProvider =
            DefaultClockProvider(context, LayoutInflater.from(context), context.resources)
        pluginManager = createPluginManager(context)
        clockRegistry =
            ClockRegistry(
                context,
                pluginManager,
                Handler.getMain(),
                isEnabled = true,
                userHandle = UserHandle.USER_OWNER,
                defaultClockProvider
            )
        pluginManager.addPluginListener(pluginListener, ClockProviderPlugin::class.java, true)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val view = inflater.inflate(R.layout.fragment_clock_custom_picker_demo, container, false)
        setUpToolbar(view)
        return view
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        recyclerView = view.requireViewById(R.id.clock_preview_card_list_demo)
        recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
        super.onViewCreated(view, savedInstanceState)
    }

    override fun getDefaultTitle(): CharSequence {
        return getString(R.string.clock_title)
    }

    private fun createPluginManager(context: Context): PluginManager {
        val instanceFactory =
            PluginInstance.Factory(
                this::class.java.classLoader,
                PluginInstance.InstanceFactory<Plugin>(),
                PluginInstance.VersionChecker(),
                privilegedPlugins,
                isDebugDevice
            )

        /*
         * let SystemUI handle plugin, in this class assume plugins are enabled
         */
        val pluginEnabler =
            object : PluginEnabler {
                override fun setEnabled(component: ComponentName) {}

                override fun setDisabled(
                    component: ComponentName,
                    @PluginEnabler.DisableReason reason: Int
                ) {}

                override fun isEnabled(component: ComponentName): Boolean {
                    return true
                }

                @PluginEnabler.DisableReason
                override fun getDisableReason(componentName: ComponentName): Int {
                    return ENABLED
                }
            }

        val pluginActionManager =
            PluginActionManager.Factory(
                context,
                context.packageManager,
                context.mainExecutor,
                Executors.newSingleThreadExecutor(),
                context.getSystemService(NotificationManager::class.java),
                pluginEnabler,
                privilegedPlugins,
                instanceFactory
            )
        return PluginManagerImpl(
            context,
            pluginActionManager,
            isDebugDevice,
            uncaughtExceptionPreHandlerManager,
            pluginEnabler,
            PluginPrefs(context),
            listOf()
        )
    }

    companion object {
        private val uncaughtExceptionPreHandlerManager =
            UncaughtExceptionPreHandlerManager_Factory.create().get()
    }

    internal class ClockRecyclerAdapter(
        val list: List<ClockMetadata>,
        val context: Context,
        val clockRegistry: ClockRegistry
    ) : RecyclerView.Adapter<ClockRecyclerAdapter.ViewHolder>() {
        class ViewHolder(val view: View, val textView: TextView, val onItemClicked: (Int) -> Unit) :
            RecyclerView.ViewHolder(view) {
            init {
                itemView.setOnClickListener { onItemClicked(absoluteAdapterPosition) }
            }
        }

        override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
            val rootView = FrameLayout(viewGroup.context)
            val textView =
                TextView(ContextThemeWrapper(viewGroup.context, R.style.SectionTitleTextStyle))
            textView.setPadding(ITEM_PADDING)
            rootView.addView(textView)
            val lp = RecyclerView.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
            rootView.setLayoutParams(lp)
            return ViewHolder(
                rootView,
                textView,
                { clockRegistry.currentClockId = list[it].clockId }
            )
        }

        override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
            viewHolder.textView.text = list[position].name
        }

        override fun getItemCount() = list.size

        companion object {
            val ITEM_PADDING = 40
        }
    }
}