<commit_before>/*
 * Copyright 2014 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.android.apps.muzei.gallery

import android.Manifest
import android.annotation.SuppressLint
import android.arch.lifecycle.Lifecycle
import android.arch.lifecycle.LifecycleOwner
import android.arch.lifecycle.LifecycleRegistry
import android.arch.lifecycle.Observer
import android.content.ContentUris
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.location.Geocoder
import android.net.Uri
import android.os.Binder
import android.os.Build
import android.os.IBinder
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.support.annotation.RequiresApi
import android.support.media.ExifInterface
import android.support.v4.content.ContextCompat
import android.text.TextUtils
import android.text.format.DateUtils
import android.util.Log
import androidx.core.database.getString
import androidx.core.net.toUri
import com.google.android.apps.muzei.api.Artwork
import com.google.android.apps.muzei.api.MuzeiArtSource
import java.io.IOException
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.ArrayList
import java.util.Random

class GalleryArtSource : MuzeiArtSource(SOURCE_NAME), LifecycleOwner {

    companion object {
        private const val TAG = "GalleryArtSource"
        private const val SOURCE_NAME = "GalleryArtSource"

        internal const val PREF_ROTATE_INTERVAL_MIN = "rotate_interval_min"

        internal const val DEFAULT_ROTATE_INTERVAL_MIN = 60 * 6

        internal const val ACTION_BIND_GALLERY = "com.google.android.apps.muzei.gallery.BIND_GALLERY"
        internal const val ACTION_PUBLISH_NEXT_GALLERY_ITEM =
                "com.google.android.apps.muzei.gallery.action.PUBLISH_NEXT_GALLERY_ITEM"
        internal const val EXTRA_FORCE_URI = "com.google.android.apps.muzei.gallery.extra.FORCE_URI"

        private val RANDOM = Random()

        @SuppressLint("SimpleDateFormat")
        private val EXIF_DATE_FORMAT = SimpleDateFormat("yyyy:MM:dd HH:mm:ss")

        private val OMIT_COUNTRY_CODES = hashSetOf("US")

        internal fun getSharedPreferences(context: Context): SharedPreferences {
            return MuzeiArtSource.getSharedPreferences(context, SOURCE_NAME)
        }
    }

    private val lifecycle = LifecycleRegistry(this)
    private val geocoder by lazy {
        Geocoder(this)
    }

    override fun getLifecycle(): Lifecycle {
        return lifecycle
    }

    override fun onCreate() {
        super.onCreate()
        lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START)

        GalleryDatabase.getInstance(this).chosenPhotoDao().chosenPhotos.observe(this,
                object : Observer<List<ChosenPhoto>> {
                    private var numImages = -1

                    override fun onChanged(chosenPhotos: List<ChosenPhoto>?) {
                        val oldCount = numImages
                        // Update the metadata
                        numImages = if (chosenPhotos != null) updateMeta(chosenPhotos) else 0
                        if (numImages == 0) {
                            // We're showing random photos so no special logic is needed
                            return
                        }

                        val currentArtworkToken = currentArtwork?.token?.toUri()
                        val foundCurrentArtwork = chosenPhotos?.find { chosenPhoto ->
                            chosenPhoto.contentUri == currentArtworkToken
                        } != null
                        if (!foundCurrentArtwork) {
                            // We're showing a removed URI
                            startService(Intent(this@GalleryArtSource, GalleryArtSource::class.java)
                                    .setAction(ACTION_PUBLISH_NEXT_GALLERY_ITEM))
                        } else if (oldCount == 0 && numImages > 0) {
                            // If we've transitioned from a count of zero to a count greater than zero
                            startService(Intent(this@GalleryArtSource, GalleryArtSource::class.java)
                                    .setAction(ACTION_PUBLISH_NEXT_GALLERY_ITEM)
                                    .putExtra(EXTRA_FORCE_URI, chosenPhotos?.get(0)?.contentUri))
                        }
                    }
                })
    }

    override fun onBind(intent: Intent?): IBinder? {
        return if (ACTION_BIND_GALLERY == intent?.action) {
            Binder()
        } else super.onBind(intent)
    }

    override fun onDestroy() {
        lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        super.onDestroy()
    }

    override fun onHandleIntent(intent: Intent?) {
        super.onHandleIntent(intent)
        if (ACTION_PUBLISH_NEXT_GALLERY_ITEM == intent?.action) {
            publishNextArtwork(intent.getParcelableExtra(EXTRA_FORCE_URI))
        }
    }

    override fun onUpdate(@UpdateReason reason: Int) {
        if (reason == UPDATE_REASON_INITIAL) {
            updateMeta(GalleryDatabase.getInstance(this).chosenPhotoDao().chosenPhotosBlocking)
        }
        publishNextArtwork(null)
    }

    private fun publishNextArtwork(forceUri: Uri?) {
        // schedule next
        scheduleNext()

        val chosenPhotos = GalleryDatabase.getInstance(this)
                .chosenPhotoDao().chosenPhotosBlocking
        val numChosenUris = chosenPhotos.size

        val lastImageUri = currentArtwork?.imageUri

        val (imageUri, token) = when {
            forceUri != null -> {
                val chosenPhoto = GalleryDatabase.getInstance(this)
                        .chosenPhotoDao().chosenPhotoBlocking(ContentUris.parseId(forceUri))<commit_msg>Only mark GalleryArtSource as started when it is bound<commit_after>/*
 * Copyright 2014 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.android.apps.muzei.gallery

import android.Manifest
import android.annotation.SuppressLint
import android.arch.lifecycle.Lifecycle
import android.arch.lifecycle.LifecycleOwner
import android.arch.lifecycle.LifecycleRegistry
import android.arch.lifecycle.Observer
import android.content.ContentUris
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.location.Geocoder
import android.net.Uri
import android.os.Binder
import android.os.Build
import android.os.IBinder
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.support.annotation.RequiresApi
import android.support.media.ExifInterface
import android.support.v4.content.ContextCompat
import android.text.TextUtils
import android.text.format.DateUtils
import android.util.Log
import androidx.core.database.getString
import androidx.core.net.toUri
import com.google.android.apps.muzei.api.Artwork
import com.google.android.apps.muzei.api.MuzeiArtSource
import java.io.IOException
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.ArrayList
import java.util.Random

class GalleryArtSource : MuzeiArtSource(SOURCE_NAME), LifecycleOwner {

    companion object {
        private const val TAG = "GalleryArtSource"
        private const val SOURCE_NAME = "GalleryArtSource"

        internal const val PREF_ROTATE_INTERVAL_MIN = "rotate_interval_min"

        internal const val DEFAULT_ROTATE_INTERVAL_MIN = 60 * 6

        internal const val ACTION_BIND_GALLERY = "com.google.android.apps.muzei.gallery.BIND_GALLERY"
        internal const val ACTION_PUBLISH_NEXT_GALLERY_ITEM =
                "com.google.android.apps.muzei.gallery.action.PUBLISH_NEXT_GALLERY_ITEM"
        internal const val EXTRA_FORCE_URI = "com.google.android.apps.muzei.gallery.extra.FORCE_URI"

        private val RANDOM = Random()

        @SuppressLint("SimpleDateFormat")
        private val EXIF_DATE_FORMAT = SimpleDateFormat("yyyy:MM:dd HH:mm:ss")

        private val OMIT_COUNTRY_CODES = hashSetOf("US")

        internal fun getSharedPreferences(context: Context): SharedPreferences {
            return MuzeiArtSource.getSharedPreferences(context, SOURCE_NAME)
        }
    }

    private val lifecycle = LifecycleRegistry(this)
    private val geocoder by lazy {
        Geocoder(this)
    }

    override fun getLifecycle(): Lifecycle {
        return lifecycle
    }

    override fun onCreate() {
        super.onCreate()
        lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)

        GalleryDatabase.getInstance(this).chosenPhotoDao().chosenPhotos.observe(this,
                object : Observer<List<ChosenPhoto>> {
                    private var numImages = -1

                    override fun onChanged(chosenPhotos: List<ChosenPhoto>?) {
                        val oldCount = numImages
                        // Update the metadata
                        numImages = if (chosenPhotos != null) updateMeta(chosenPhotos) else 0
                        if (numImages == 0) {
                            // We're showing random photos so no special logic is needed
                            return
                        }

                        val currentArtworkToken = currentArtwork?.token?.toUri()
                        val foundCurrentArtwork = chosenPhotos?.find { chosenPhoto ->
                            chosenPhoto.contentUri == currentArtworkToken
                        } != null
                        if (!foundCurrentArtwork) {
                            // We're showing a removed URI
                            startService(Intent(this@GalleryArtSource, GalleryArtSource::class.java)
                                    .setAction(ACTION_PUBLISH_NEXT_GALLERY_ITEM))
                        } else if (oldCount == 0 && numImages > 0) {
                            // If we've transitioned from a count of zero to a count greater than zero
                            startService(Intent(this@GalleryArtSource, GalleryArtSource::class.java)
                                    .setAction(ACTION_PUBLISH_NEXT_GALLERY_ITEM)
                                    .putExtra(EXTRA_FORCE_URI, chosenPhotos?.get(0)?.contentUri))
                        }
                    }
                })
    }

    override fun onBind(intent: Intent?): IBinder? {
        return if (ACTION_BIND_GALLERY == intent?.action) {
            lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START)
            Binder()
        } else super.onBind(intent)
    }

    override fun onDestroy() {
        lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        super.onDestroy()
    }

    override fun onHandleIntent(intent: Intent?) {
        super.onHandleIntent(intent)
        if (ACTION_PUBLISH_NEXT_GALLERY_ITEM == intent?.action) {
            publishNextArtwork(intent.getParcelableExtra(EXTRA_FORCE_URI))
        }
    }

    override fun onUpdate(@UpdateReason reason: Int) {
        updateMeta(GalleryDatabase.getInstance(this).chosenPhotoDao().chosenPhotosBlocking)
        publishNextArtwork(null)
    }

    private fun publishNextArtwork(forceUri: Uri?) {
        // schedule next
        scheduleNext()

        val chosenPhotos = GalleryDatabase.getInstance(this)
                .chosenPhotoDao().chosenPhotosBlocking
        val numChosenUris = chosenPhotos.size

        val lastImageUri = currentArtwork?.imageUri

        val (imageUri, token) = when {
            forceUri != null -> {
                val chosenPhoto = GalleryDatabase.getInstance(this)
                        .chosenPhotoDao().chosenPhotoBlocking(ContentUris.parseId(forceUri))
{'fraction_non_alphanumeric': 0.07531347962382445, 'fraction_numerical': 0.0028213166144200625, 'mean_word_length': 2.4780594167348053, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4944471', 'n_tokens_mistral': 3455, 'n_tokens_neox': 3280, 'n_words': 769}