1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.calendar
17 
18 import android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME
19 import android.provider.CalendarContract.EXTRA_EVENT_END_TIME
20 import android.provider.CalendarContract.Attendees.ATTENDEE_STATUS
21 import android.app.ActionBar
22 import android.app.Activity
23 import android.app.FragmentManager
24 import android.app.FragmentTransaction
25 import android.content.Intent
26 import android.content.res.Resources
27 import android.database.ContentObserver
28 import android.net.Uri
29 import android.os.Bundle
30 import android.os.Handler
31 import android.provider.CalendarContract
32 import android.provider.CalendarContract.Attendees
33 import android.util.Log
34 import android.widget.Toast
35 
36 class EventInfoActivity : Activity() {
37     private var mInfoFragment: EventInfoFragment? = null
38     private var mStartMillis: Long = 0
39     private var mEndMillis: Long = 0
40     private var mEventId: Long = 0
41 
42     // Create an observer so that we can update the views whenever a
43     // Calendar event changes.
44     private val mObserver: ContentObserver = object : ContentObserver(Handler()) {
45         @Override
deliverSelfNotificationsnull46         override fun deliverSelfNotifications(): Boolean {
47             return false
48         }
49 
50         @Override
onChangenull51         override fun onChange(selfChange: Boolean) {
52             if (selfChange) return
53             val temp = mInfoFragment
54             if (temp != null) {
55                 mInfoFragment?.reloadEvents()
56             }
57         }
58     }
59 
60     @Override
onCreatenull61     protected override fun onCreate(icicle: Bundle?) {
62         super.onCreate(icicle)
63 
64         // Get the info needed for the fragment
65         val intent: Intent = getIntent()
66         var attendeeResponse = 0
67         mEventId = -1
68         var isDialog = false
69         if (icicle != null) {
70             mEventId = icicle.getLong(EventInfoFragment.BUNDLE_KEY_EVENT_ID)
71             mStartMillis = icicle.getLong(EventInfoFragment.BUNDLE_KEY_START_MILLIS)
72             mEndMillis = icicle.getLong(EventInfoFragment.BUNDLE_KEY_END_MILLIS)
73             attendeeResponse = icicle.getInt(EventInfoFragment.BUNDLE_KEY_ATTENDEE_RESPONSE)
74             isDialog = icicle.getBoolean(EventInfoFragment.BUNDLE_KEY_IS_DIALOG)
75         } else if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
76             mStartMillis = intent.getLongExtra(EXTRA_EVENT_BEGIN_TIME, 0)
77             mEndMillis = intent.getLongExtra(EXTRA_EVENT_END_TIME, 0)
78             attendeeResponse = intent.getIntExtra(
79                     ATTENDEE_STATUS,
80                     Attendees.ATTENDEE_STATUS_NONE
81             )
82             val data: Uri? = intent.getData()
83             if (data != null) {
84                 try {
85                     val pathSegments = data.getPathSegments()
86                     val size: Int = pathSegments.size
87                     if (size > 2 && "EventTime".equals(pathSegments[2])) {
88                         // Support non-standard VIEW intent format:
89                         // dat = content://com.android.calendar/events/[id]/EventTime/[start]/[end]
90                         mEventId = pathSegments[1].toLong()
91                         if (size > 4) {
92                             mStartMillis = pathSegments[3].toLong()
93                             mEndMillis = pathSegments[4].toLong()
94                         }
95                     } else {
96                         mEventId = data.getLastPathSegment() as Long
97                     }
98                 } catch (e: NumberFormatException) {
99                     if (mEventId == -1L) {
100                         // do nothing here , deal with it later
101                     } else if (mStartMillis == 0L || mEndMillis == 0L) {
102                         // Parsing failed on the start or end time , make sure the times were not
103                         // pulled from the intent's extras and reset them.
104                         mStartMillis = 0
105                         mEndMillis = 0
106                     }
107                 }
108             }
109         }
110         if (mEventId == -1L) {
111             Log.w(TAG, "No event id")
112             Toast.makeText(this, R.string.event_not_found, Toast.LENGTH_SHORT).show()
113             finish()
114         }
115 
116         // If we do not support showing full screen event info in this configuration,
117         // close the activity and show the event in AllInOne.
118         val res: Resources = getResources()
119         if (!res.getBoolean(R.bool.agenda_show_event_info_full_screen) &&
120                 !res.getBoolean(R.bool.show_event_info_full_screen)
121         ) {
122             CalendarController.getInstance(this)
123                     ?.launchViewEvent(mEventId, mStartMillis, mEndMillis, attendeeResponse)
124             finish()
125             return
126         }
127         setContentView(R.layout.simple_frame_layout)
128 
129         // Get the fragment if exists
130         mInfoFragment = getFragmentManager().findFragmentById(R.id.main_frame) as EventInfoFragment
131 
132         // Remove the application title
133         val bar: ActionBar? = getActionBar()
134         if (bar != null) {
135             bar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP or ActionBar.DISPLAY_SHOW_HOME)
136         }
137 
138         // Create a new fragment if none exists
139         if (mInfoFragment == null) {
140             val fragmentManager: FragmentManager = getFragmentManager()
141             val ft: FragmentTransaction = fragmentManager.beginTransaction()
142             mInfoFragment = EventInfoFragment(
143                     this,
144                     mEventId,
145                     mStartMillis,
146                     mEndMillis,
147                     attendeeResponse,
148                     isDialog,
149                     if (isDialog) EventInfoFragment.DIALOG_WINDOW_STYLE
150                     else EventInfoFragment.FULL_WINDOW_STYLE
151             )
152             ft.replace(R.id.main_frame, mInfoFragment)
153             ft.commit()
154         }
155     }
156 
157     @Override
onNewIntentnull158     protected override fun onNewIntent(intent: Intent?) {
159         // From the Android Dev Guide: "It's important to note that when
160         // onNewIntent(Intent) is called, the Activity has not been restarted,
161         // so the getIntent() method will still return the Intent that was first
162         // received with onCreate(). This is why setIntent(Intent) is called
163         // inside onNewIntent(Intent) (just in case you call getIntent() at a
164         // later time)."
165         setIntent(intent)
166     }
167 
168     @Override
onSaveInstanceStatenull169     override fun onSaveInstanceState(outState: Bundle) {
170         super.onSaveInstanceState(outState)
171     }
172 
173     @Override
onResumenull174     protected override fun onResume() {
175         super.onResume()
176         getContentResolver().registerContentObserver(
177                 CalendarContract.Events.CONTENT_URI,
178                 true, mObserver
179         )
180     }
181 
182     @Override
onPausenull183     protected override fun onPause() {
184         super.onPause()
185         getContentResolver().unregisterContentObserver(mObserver)
186     }
187 
188     @Override
onDestroynull189     protected override fun onDestroy() {
190         super.onDestroy()
191     }
192 
193     companion object {
194         private const val TAG = "EventInfoActivity"
195     }
196 }