Remove phone activities and implement one-pane
The primary purpose of this CL is to remove phone activities, so the one pane implementation is very much temporary and primitive, but it should offer minimal operations. Change-Id: If57f81db7c605c95664d49044a5cc082beda59c0
Before Width: | Height: | Size: 443 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 916 B |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 381 B |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 331 B |
Before Width: | Height: | Size: 723 B |
Before Width: | Height: | Size: 797 B |
Before Width: | Height: | Size: 634 B |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 310 B |
Before Width: | Height: | Size: 674 B |
Before Width: | Height: | Size: 728 B |
|
@ -1,29 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<fragment
|
||||
android:id="@+id/account_folder_list_fragment"
|
||||
class="com.android.email.activity.AccountFolderListFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
</LinearLayout>
|
|
@ -1,102 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<com.android.email.activity.AccountFolderListItem
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingRight="4dip">
|
||||
<View
|
||||
android:id="@+id/chip"
|
||||
android:background="@drawable/appointment_indicator_leftside_1"
|
||||
android:layout_width="4dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true" />
|
||||
<ImageView
|
||||
android:id="@+id/folder_icon"
|
||||
android:layout_width="30dip"
|
||||
android:layout_height="30dip"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginLeft="4dip"
|
||||
android:layout_marginRight="4dip"
|
||||
android:minWidth="30dip"
|
||||
android:src="@drawable/ic_list_folder" />
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_weight="1">
|
||||
<LinearLayout
|
||||
android:id="@+id/subject"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dip"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/status"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorTertiary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/new_message_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="4dip"
|
||||
android:background="@drawable/ind_unread"
|
||||
style="@style/unreadCount"/>
|
||||
<TextView
|
||||
android:id="@+id/all_message_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="4dip"
|
||||
android:background="@drawable/ind_sum"
|
||||
style="@style/unreadCount"/>
|
||||
</LinearLayout>
|
||||
<ImageView
|
||||
android:id="@+id/default_sender"
|
||||
android:layout_width="12dip"
|
||||
android:layout_height="12dip"
|
||||
android:minWidth="12dip"
|
||||
android:layout_margin="5dip"
|
||||
android:src="@drawable/ind_default"/>
|
||||
<View
|
||||
android:id="@+id/folder_separator"
|
||||
android:background="@color/account_folder_list_item_separator"
|
||||
android:layout_width="1dip"
|
||||
android:layout_height="40dip"
|
||||
android:layout_marginLeft="5dip" />
|
||||
<ImageView
|
||||
android:id="@+id/folder_button"
|
||||
android:layout_width="40dip"
|
||||
android:layout_height="40dip"
|
||||
android:layout_alignParentRight="true"
|
||||
android:minWidth="30dip"
|
||||
android:paddingTop="5dip"
|
||||
android:paddingLeft="5dip"
|
||||
android:src="@drawable/btn_folder"/>
|
||||
</com.android.email.activity.AccountFolderListItem>
|
|
@ -35,10 +35,16 @@
|
|||
android:ellipsize="end"
|
||||
android:background="#ffff66"
|
||||
/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fragment_placeholder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
<!-- TODO temporarily gone -->
|
||||
<include
|
||||
layout="@layout/message_command_button_view"
|
||||
android:id="@+id/message_command_buttons"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<include layout="@layout/connection_error_banner" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/mailbox_list_fragment"
|
||||
class="com.android.email.activity.MailboxListFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
|
@ -1,31 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<include layout="@layout/connection_error_banner" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/message_list_fragment"
|
||||
class="com.android.email.activity.MessageListFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1" />
|
||||
</LinearLayout>
|
|
@ -1,53 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/white">
|
||||
<fragment
|
||||
android:id="@+id/message_view_fragment"
|
||||
class="com.android.email.activity.MessageViewFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:id="@+id/button_panel"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="5dip"
|
||||
android:paddingLeft="4dip"
|
||||
android:paddingRight="4dip"
|
||||
android:paddingBottom="1dip"
|
||||
>
|
||||
<Button
|
||||
android:id="@+id/moveToNewer"
|
||||
android:text="@string/message_view_move_to_newer"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="0dip"
|
||||
android:layout_weight="1" />
|
||||
<Button
|
||||
android:id="@+id/moveToOlder"
|
||||
android:text="@string/message_view_move_to_older"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="0dip"
|
||||
android:layout_weight="1" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
|
@ -1,40 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<!-- xlarge -->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/send"
|
||||
android:title="@string/send_action"
|
||||
android:showAsAction="always|withText"
|
||||
android:icon="@drawable/ic_menu_send_holo_light"
|
||||
android:alphabeticShortcut="s"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/save"
|
||||
android:title="@string/save_draft_action"
|
||||
android:showAsAction="always"
|
||||
android:alphabeticShortcut="d"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/discard"
|
||||
android:title="@string/discard_action"
|
||||
android:showAsAction="always"
|
||||
android:icon="@drawable/ic_menu_trash_holo_light"
|
||||
android:alphabeticShortcut="q"
|
||||
/>
|
||||
</menu>
|
|
@ -1,28 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/open_folder"
|
||||
android:title="@string/open_action" />
|
||||
<item android:id="@+id/compose"
|
||||
android:title="@string/compose_action" />
|
||||
<item android:id="@+id/refresh_account"
|
||||
android:title="@string/refresh_action" />
|
||||
<item android:id="@+id/edit_account"
|
||||
android:title="@string/account_settings_action" />
|
||||
<item android:id="@+id/delete_account"
|
||||
android:title="@string/remove_account_action" />
|
||||
</menu>
|
|
@ -1,45 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/compose"
|
||||
android:alphabeticShortcut="c"
|
||||
android:title="@string/compose_action"
|
||||
android:icon="@drawable/ic_menu_compose"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/check_mail"
|
||||
android:alphabeticShortcut="r"
|
||||
android:title="@string/refresh_action"
|
||||
android:icon="@drawable/ic_menu_refresh"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/add_new_account"
|
||||
android:title="@string/add_account_action"
|
||||
android:icon="@android:drawable/ic_menu_add"
|
||||
/>
|
||||
<item android:id="@+id/account_settings"
|
||||
android:title="@string/account_settings_action"
|
||||
android:icon="@android:drawable/ic_menu_preferences"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<!--
|
||||
<item android:id="@+id/search"
|
||||
android:title="@string/search_action" />
|
||||
<item android:id="@+id/preferences"
|
||||
android:title="@string/preferences_action" />
|
||||
-->
|
||||
</menu>
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/open_folder"
|
||||
android:title="@string/open_action" />
|
||||
<item android:id="@+id/check_mail"
|
||||
android:title="@string/refresh_action" />
|
||||
</menu>
|
|
@ -1,34 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/compose"
|
||||
android:alphabeticShortcut="c"
|
||||
android:title="@string/compose_action"
|
||||
android:icon="@drawable/ic_menu_compose"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/refresh"
|
||||
android:alphabeticShortcut="r"
|
||||
android:title="@string/refresh_action"
|
||||
android:icon="@drawable/ic_menu_refresh"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/account_settings"
|
||||
android:title="@string/account_settings_action"
|
||||
android:icon="@android:drawable/ic_menu_preferences"
|
||||
/>
|
||||
</menu>
|
|
@ -14,8 +14,6 @@
|
|||
limitations under the License.
|
||||
-->
|
||||
|
||||
<!-- small -->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/send"
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<!-- This context menu is shown for message lists except in trash, outbox, or drafts -->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/open" android:title="@string/open_action" />
|
||||
<item android:id="@+id/delete" android:title="@string/delete_action" />
|
||||
<item android:id="@+id/forward" android:title="@string/forward_action" />
|
||||
<item android:id="@+id/reply_all" android:title="@string/reply_all_action" />
|
||||
<item android:id="@+id/reply" android:title="@string/reply_action" />
|
||||
<item android:id="@+id/mark_as_read" android:title="@string/mark_as_read_action" />
|
||||
</menu>
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<!-- This context menu is shown for drafts message lists -->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/open" android:title="@string/open_action" />
|
||||
<item android:id="@+id/delete" android:title="@string/discard_action" />
|
||||
</menu>
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<!-- This context menu is shown for outbox message lists -->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/open" android:title="@string/open_action" />
|
||||
<item android:id="@+id/delete" android:title="@string/discard_action" />
|
||||
</menu>
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<!-- This context menu is shown for trash message lists -->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/open" android:title="@string/open_action" />
|
||||
<item android:id="@+id/delete" android:title="@string/delete_action" />
|
||||
</menu>
|
|
@ -1,45 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/refresh"
|
||||
android:alphabeticShortcut="r"
|
||||
android:title="@string/refresh_action"
|
||||
android:icon="@drawable/ic_menu_refresh_holo_light"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/compose"
|
||||
android:alphabeticShortcut="c"
|
||||
android:title="@string/compose_action"
|
||||
android:icon="@drawable/ic_menu_compose_holo_light"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/folders"
|
||||
android:title="@string/folders_action"
|
||||
android:icon="@drawable/ic_menu_folder"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/accounts"
|
||||
android:title="@string/accounts_action"
|
||||
android:icon="@drawable/ic_menu_account_list"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/account_settings"
|
||||
android:title="@string/account_settings_action"
|
||||
android:icon="@android:drawable/ic_menu_preferences"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
</menu>
|
|
@ -1,48 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/delete"
|
||||
android:alphabeticShortcut="q"
|
||||
android:title="@string/delete_action"
|
||||
android:icon="@android:drawable/ic_menu_delete"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/forward"
|
||||
android:alphabeticShortcut="f"
|
||||
android:title="@string/forward_action"
|
||||
android:icon="@drawable/ic_menu_forward_mail"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/reply"
|
||||
android:alphabeticShortcut="r"
|
||||
android:title="@string/reply_action"
|
||||
android:icon="@drawable/ic_menu_reply"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/reply_all"
|
||||
android:alphabeticShortcut="a"
|
||||
android:title="@string/reply_all_action"
|
||||
android:icon="@drawable/ic_menu_reply_all"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/mark_as_unread"
|
||||
android:alphabeticShortcut="u"
|
||||
android:title="@string/mark_as_unread_action"
|
||||
android:icon="@drawable/ic_menu_mark_unread_holo_light"
|
||||
/>
|
||||
</menu>
|
|
@ -1,313 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.activity;
|
||||
|
||||
import com.android.email.Controller;
|
||||
import com.android.email.ControllerResultUiThreadWrapper;
|
||||
import com.android.email.Email;
|
||||
import com.android.email.NotificationController;
|
||||
import com.android.email.R;
|
||||
import com.android.email.activity.setup.AccountSettingsXL;
|
||||
import com.android.email.activity.setup.AccountSetupBasics;
|
||||
import com.android.emailcommon.mail.MessagingException;
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.Account;
|
||||
import com.android.emailcommon.provider.EmailContent.Mailbox;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class AccountFolderList extends Activity implements AccountFolderListFragment.Callback {
|
||||
private static final int DIALOG_REMOVE_ACCOUNT = 1;
|
||||
|
||||
private static final String ICICLE_SELECTED_ACCOUNT = "com.android.email.selectedAccount";
|
||||
private EmailContent.Account mSelectedContextAccount;
|
||||
|
||||
// UI Support
|
||||
private AccountFolderListFragment mListFragment;
|
||||
|
||||
private Controller.Result mControllerCallback;
|
||||
|
||||
/**
|
||||
* Start the Accounts list activity. Uses the CLEAR_TOP flag which means that other stacked
|
||||
* activities may be killed in order to get back to Accounts.
|
||||
*/
|
||||
public static void actionShowAccounts(Context context) {
|
||||
Intent i = new Intent(context, AccountFolderList.class);
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
context.startActivity(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
ActivityHelper.debugSetWindowFlags(this);
|
||||
|
||||
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||
setContentView(R.layout.account_folder_list);
|
||||
|
||||
mControllerCallback = new ControllerResultUiThreadWrapper<ControllerResults>(
|
||||
new Handler(), new ControllerResults());
|
||||
mListFragment =
|
||||
(AccountFolderListFragment) getFragmentManager()
|
||||
.findFragmentById(R.id.account_folder_list_fragment);
|
||||
mListFragment.bindActivityInfo(this);
|
||||
|
||||
if (icicle != null && icicle.containsKey(ICICLE_SELECTED_ACCOUNT)) {
|
||||
mSelectedContextAccount = (Account) icicle.getParcelable(ICICLE_SELECTED_ACCOUNT);
|
||||
}
|
||||
|
||||
// Halt the progress indicator (we'll display it later when needed)
|
||||
setProgressBarIndeterminate(true);
|
||||
setProgressBarIndeterminateVisibility(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
if (mSelectedContextAccount != null) {
|
||||
outState.putParcelable(ICICLE_SELECTED_ACCOUNT, mSelectedContextAccount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
Controller.getInstance(getApplication()).removeResultCallback(mControllerCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
NotificationManager notifMgr = (NotificationManager)
|
||||
getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notifMgr.cancel(1);
|
||||
|
||||
Controller.getInstance(getApplication()).addResultCallback(mControllerCallback);
|
||||
|
||||
// Exit immediately if the accounts list has changed (e.g. externally deleted)
|
||||
if (Email.getNotifyUiAccountsChanged()) {
|
||||
Welcome.actionStart(this);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
private void onAddNewAccount() {
|
||||
AccountSetupBasics.actionNewAccount(this);
|
||||
}
|
||||
|
||||
/* Implements AccountFolderListFragment.Callback */
|
||||
public void onEditAccount(long accountId) {
|
||||
AccountSettingsXL.actionSettings(this, -1);
|
||||
}
|
||||
|
||||
/* Implements AccountFolderListFragment.Callback */
|
||||
public void onRefresh(long accountId) {
|
||||
if (accountId == -1) {
|
||||
// TODO implement a suitable "Refresh all accounts" / "check mail" comment in Controller
|
||||
// TODO this is temp
|
||||
Toast.makeText(this, getString(R.string.account_folder_list_refresh_toast),
|
||||
Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
showProgressIcon(true);
|
||||
Controller.getInstance(getApplication()).updateMailboxList(accountId);
|
||||
// TODO update the inbox too
|
||||
}
|
||||
}
|
||||
|
||||
/* Implements AccountFolderListFragment.Callback */
|
||||
public void onCompose(long accountId) {
|
||||
if (accountId == -1) {
|
||||
accountId = Account.getDefaultAccountId(this);
|
||||
}
|
||||
if (accountId != -1) {
|
||||
MessageCompose.actionCompose(this, accountId);
|
||||
} else {
|
||||
onAddNewAccount();
|
||||
}
|
||||
}
|
||||
|
||||
/* Implements AccountFolderListFragment.Callback */
|
||||
public void onDeleteAccount(long accountId) {
|
||||
mSelectedContextAccount = Account.restoreAccountWithId(this, accountId);
|
||||
showDialog(DIALOG_REMOVE_ACCOUNT);
|
||||
}
|
||||
|
||||
/* Implements AccountFolderListFragment.Callback */
|
||||
public void onOpenAccount(long accountId) {
|
||||
MessageList.actionHandleAccount(this, accountId, Mailbox.TYPE_INBOX);
|
||||
}
|
||||
|
||||
/* Implements AccountFolderListFragment.Callback */
|
||||
public void onOpenMailbox(long mailboxId) {
|
||||
MessageList.actionHandleMailbox(this, mailboxId);
|
||||
}
|
||||
|
||||
/* Implements AccountFolderListFragment.Callback */
|
||||
public void onOpenMailboxes(long accountId) {
|
||||
MailboxList.actionHandleAccount(this, accountId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(int id, Bundle args) {
|
||||
switch (id) {
|
||||
case DIALOG_REMOVE_ACCOUNT:
|
||||
return createRemoveAccountDialog();
|
||||
}
|
||||
return super.onCreateDialog(id, args);
|
||||
}
|
||||
|
||||
private Dialog createRemoveAccountDialog() {
|
||||
final Activity activity = this;
|
||||
return new AlertDialog.Builder(this)
|
||||
.setIconAttribute(android.R.attr.alertDialogIcon)
|
||||
.setTitle(R.string.account_delete_dlg_title)
|
||||
.setMessage(getString(R.string.account_delete_dlg_instructions_fmt,
|
||||
mSelectedContextAccount.getDisplayName()))
|
||||
.setPositiveButton(R.string.okay_action, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
final long accountId = mSelectedContextAccount.mId;
|
||||
dismissDialog(DIALOG_REMOVE_ACCOUNT);
|
||||
// TODO Do this automatically in the NotificationController as part of a
|
||||
// ContentObserver
|
||||
// Dismiss new message notification.
|
||||
NotificationController.getInstance(activity)
|
||||
.cancelNewMessageNotification(accountId);
|
||||
int numAccounts = EmailContent.count(activity,
|
||||
Account.CONTENT_URI, null, null);
|
||||
mListFragment.hideDeletingAccount(mSelectedContextAccount.mId);
|
||||
|
||||
Controller.getInstance(activity).deleteAccount(accountId);
|
||||
if (numAccounts == 1) {
|
||||
AccountSetupBasics.actionNewAccount(activity);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel_action, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
dismissDialog(DIALOG_REMOVE_ACCOUNT);
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a cached dialog with current values (e.g. account name)
|
||||
*/
|
||||
@Override
|
||||
public void onPrepareDialog(int id, Dialog dialog, Bundle args) {
|
||||
switch (id) {
|
||||
case DIALOG_REMOVE_ACCOUNT:
|
||||
AlertDialog alert = (AlertDialog) dialog;
|
||||
alert.setMessage(getString(R.string.account_delete_dlg_instructions_fmt,
|
||||
mSelectedContextAccount.getDisplayName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.add_new_account:
|
||||
onAddNewAccount();
|
||||
break;
|
||||
case R.id.check_mail:
|
||||
onRefresh(-1);
|
||||
break;
|
||||
case R.id.compose:
|
||||
onCompose(-1);
|
||||
break;
|
||||
case R.id.account_settings:
|
||||
onEditAccount(-1);
|
||||
break;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.account_folder_list_option, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void showProgressIcon(boolean show) {
|
||||
setProgressBarIndeterminateVisibility(show);
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller results listener. We wrap it with {@link ControllerResultUiThreadWrapper},
|
||||
* so all methods are called on the UI thread.
|
||||
*/
|
||||
private class ControllerResults extends Controller.Result {
|
||||
@Override
|
||||
public void updateMailboxListCallback(MessagingException result, long accountKey,
|
||||
int progress) {
|
||||
updateProgress(result, progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMailboxCallback(MessagingException result, long accountKey,
|
||||
long mailboxKey, int progress, int numNewMessages,
|
||||
ArrayList<Long> addedMessages) {
|
||||
updateProgress(result, progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceCheckMailCallback(MessagingException result, long accountId,
|
||||
long mailboxId, int progress, long tag) {
|
||||
updateProgress(result, progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMailCallback(MessagingException result, long accountId, long messageId,
|
||||
int progress) {
|
||||
}
|
||||
|
||||
private void updateProgress(MessagingException result, int progress) {
|
||||
showProgressIcon(result == null && progress < 100);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,474 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.activity;
|
||||
|
||||
import com.android.email.Controller;
|
||||
import com.android.email.ControllerResultUiThreadWrapper;
|
||||
import com.android.email.R;
|
||||
import com.android.emailcommon.mail.MessagingException;
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.Account;
|
||||
import com.android.emailcommon.provider.EmailContent.Mailbox;
|
||||
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Message;
|
||||
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
||||
import com.android.emailcommon.utility.Utility;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ListFragment;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.database.MatrixCursor.RowBuilder;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.CursorAdapter;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
public class AccountFolderListFragment extends ListFragment
|
||||
implements OnItemClickListener, AccountsAdapter.Callback {
|
||||
|
||||
// UI Support
|
||||
private Activity mActivity;
|
||||
private ListView mListView;
|
||||
private Callback mCallback;
|
||||
|
||||
// Tasks and Data
|
||||
private AccountsAdapter mListAdapter;
|
||||
private LoadAccountsTask mLoadAccountsTask;
|
||||
private Controller.Result mControllerCallback;
|
||||
|
||||
private static final String FAVORITE_COUNT_SELECTION =
|
||||
MessageColumns.FLAG_FAVORITE + "= 1";
|
||||
private static final String MAILBOX_TYPE_SELECTION =
|
||||
MailboxColumns.TYPE + " =?";
|
||||
private static final String MAILBOX_ID_SELECTION =
|
||||
MessageColumns.MAILBOX_KEY + " =?";
|
||||
private static final String[] MAILBOX_SUM_OF_UNREAD_COUNT_PROJECTION = new String [] {
|
||||
"sum(" + MailboxColumns.UNREAD_COUNT + ")"
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback interface that owning activities must implement
|
||||
*/
|
||||
public interface Callback {
|
||||
/** Called when the user clicks on a specific account */
|
||||
public void onOpenAccount(long accountId);
|
||||
/** Called when the user clicks on a specific (currently, only magic mailbox) */
|
||||
public void onOpenMailbox(long mailboxId);
|
||||
/** Called when the user clicks to open the mailbox list for a specific account */
|
||||
public void onOpenMailboxes(long accountId);
|
||||
/** Begin composing a message in a specific account, or -1 for the default account */
|
||||
public void onCompose(long accountId);
|
||||
/** Begin refreshing a specific account, or -1 for all accounts */
|
||||
public void onRefresh(long accountId);
|
||||
/** Begin edit settings for a specific account */
|
||||
public void onEditAccount(long accountId);
|
||||
/** Delete a specific account */
|
||||
public void onDeleteAccount(long accountId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to do initial creation of a fragment. This is called after
|
||||
* {@link #onAttach(Activity)} and before {@link #onActivityCreated(Bundle)}.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by activity during onCreate() to bind additional information
|
||||
* @param callback if non-null, UI clicks (e.g. refresh or open) will be delivered here
|
||||
*/
|
||||
public void bindActivityInfo(Callback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the fragment is instantiated, but not yet displayed.
|
||||
*/
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
mActivity = getActivity();
|
||||
|
||||
mListView = getListView();
|
||||
mListView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_INSET);
|
||||
mListView.setOnItemClickListener(this);
|
||||
mListView.setLongClickable(true);
|
||||
registerForContextMenu(mListView);
|
||||
|
||||
mControllerCallback = new ControllerResultUiThreadWrapper<ControllerResults>(
|
||||
new Handler(), new ControllerResults());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the Fragment is visible to the user.
|
||||
*/
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the fragment is visible to the user and actively running.
|
||||
*/
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Controller.getInstance(mActivity).addResultCallback(mControllerCallback);
|
||||
updateAccounts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the fragment is no longer displayed
|
||||
*/
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
Controller.getInstance(mActivity).removeResultCallback(mControllerCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the Fragment is no longer started.
|
||||
*/
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
Utility.cancelTaskInterrupt(mLoadAccountsTask);
|
||||
mLoadAccountsTask = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the fragment is no longer in use.
|
||||
*/
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mListAdapter != null) {
|
||||
mListAdapter.changeCursor(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo info) {
|
||||
super.onCreateContextMenu(menu, v, info);
|
||||
AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) info;
|
||||
if (mListAdapter.isMailbox(menuInfo.position)) {
|
||||
Cursor c = (Cursor) mListView.getItemAtPosition(menuInfo.position);
|
||||
String displayName = c.getString(Account.CONTENT_DISPLAY_NAME_COLUMN);
|
||||
menu.setHeaderTitle(displayName);
|
||||
mActivity.getMenuInflater()
|
||||
.inflate(R.menu.account_folder_list_smart_folder_context, menu);
|
||||
} else if (mListAdapter.isAccount(menuInfo.position)) {
|
||||
Cursor c = (Cursor) mListView.getItemAtPosition(menuInfo.position);
|
||||
String accountName = c.getString(Account.CONTENT_DISPLAY_NAME_COLUMN);
|
||||
menu.setHeaderTitle(accountName);
|
||||
mActivity.getMenuInflater().inflate(R.menu.account_folder_list_context, menu);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
AdapterView.AdapterContextMenuInfo menuInfo =
|
||||
(AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
|
||||
|
||||
// Drop the event if there's nowhere to send it (it's probably late-arriving)
|
||||
if (mCallback == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mListAdapter.isMailbox(menuInfo.position)) {
|
||||
Cursor c = (Cursor) mListView.getItemAtPosition(menuInfo.position);
|
||||
long id = c.getLong(AccountsAdapter.MAILBOX_COLUMN_ID);
|
||||
switch (item.getItemId()) {
|
||||
case R.id.open_folder:
|
||||
mCallback.onOpenMailbox(id);
|
||||
break;
|
||||
case R.id.check_mail:
|
||||
mCallback.onRefresh(-1);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
} else if (mListAdapter.isAccount(menuInfo.position)) {
|
||||
Cursor c = (Cursor) mListView.getItemAtPosition(menuInfo.position);
|
||||
long accountId = c.getLong(Account.CONTENT_ID_COLUMN);
|
||||
switch (item.getItemId()) {
|
||||
case R.id.open_folder:
|
||||
mCallback.onOpenAccount(accountId);
|
||||
break;
|
||||
case R.id.compose:
|
||||
mCallback.onCompose(accountId);
|
||||
break;
|
||||
case R.id.refresh_account:
|
||||
mCallback.onRefresh(accountId);
|
||||
break;
|
||||
case R.id.edit_account:
|
||||
mCallback.onEditAccount(accountId);
|
||||
break;
|
||||
case R.id.delete_account:
|
||||
mCallback.onDeleteAccount(accountId);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Implements OnItemClickListener.onItemClick */
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
// Drop the event if there's nowhere to send it (it's probably late-arriving)
|
||||
if (mCallback == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mListAdapter.isMailbox(position)) {
|
||||
mCallback.onOpenMailbox(id);
|
||||
} else if (mListAdapter.isAccount(position)) {
|
||||
mCallback.onOpenAccount(id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Implements AccountsAdapter.Controller */
|
||||
public void onClickAccountFolders(long accountId) {
|
||||
if (mCallback != null) {
|
||||
mCallback.onOpenMailboxes(accountId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger accounts list reload
|
||||
*/
|
||||
private void updateAccounts() {
|
||||
Utility.cancelTaskInterrupt(mLoadAccountsTask);
|
||||
mLoadAccountsTask = (LoadAccountsTask) new LoadAccountsTask().execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by container to mark an account as "being deleted" (we quickly hide it)
|
||||
*/
|
||||
public void hideDeletingAccount(long accountId) {
|
||||
mListAdapter.addOnDeletingAccount(accountId);
|
||||
}
|
||||
|
||||
private static int getUnreadCountByMailboxType(Context context, int type) {
|
||||
int count = 0;
|
||||
Cursor c = context.getContentResolver().query(Mailbox.CONTENT_URI,
|
||||
MAILBOX_SUM_OF_UNREAD_COUNT_PROJECTION,
|
||||
MAILBOX_TYPE_SELECTION,
|
||||
new String[] { String.valueOf(type) }, null);
|
||||
|
||||
try {
|
||||
if (c.moveToFirst()) {
|
||||
return c.getInt(0);
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private static int getCountByMailboxType(Context context, int type) {
|
||||
int count = 0;
|
||||
Cursor c = context.getContentResolver().query(Mailbox.CONTENT_URI,
|
||||
EmailContent.ID_PROJECTION, MAILBOX_TYPE_SELECTION,
|
||||
new String[] { String.valueOf(type) }, null);
|
||||
|
||||
try {
|
||||
c.moveToPosition(-1);
|
||||
while (c.moveToNext()) {
|
||||
count += EmailContent.count(context, Message.CONTENT_URI,
|
||||
MAILBOX_ID_SELECTION,
|
||||
new String[] {
|
||||
String.valueOf(c.getLong(EmailContent.ID_PROJECTION_COLUMN)) });
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the group and child cursors that support the summary views (aka "at a glance").
|
||||
*
|
||||
* This is a placeholder implementation with significant problems that need to be addressed:
|
||||
*
|
||||
* TODO: We should only show summary mailboxes if they are non-empty. So there needs to be
|
||||
* a more dynamic child-cursor here, probably listening for update notifications on a number
|
||||
* of other internally-held queries such as count-of-inbox, count-of-unread, etc.
|
||||
*
|
||||
* TODO: This simple list is incomplete. For example, we probably want drafts, outbox, and
|
||||
* (maybe) sent (again, these would be displayed only when non-empty).
|
||||
*
|
||||
* TODO: We need a way to count total unread in all inboxes (probably with some provider help)
|
||||
*
|
||||
* TODO: We need a way to count total # messages in all other summary boxes (probably with
|
||||
* some provider help).
|
||||
*
|
||||
* TODO use narrower account projection (see LoadAccountsTask)
|
||||
*/
|
||||
private MatrixCursor getSummaryChildCursor() {
|
||||
MatrixCursor childCursor = new MatrixCursor(AccountsAdapter.MAILBOX_PROJECTION);
|
||||
int count;
|
||||
RowBuilder row;
|
||||
// TYPE_INBOX
|
||||
count = getUnreadCountByMailboxType(mActivity, Mailbox.TYPE_INBOX);
|
||||
row = childCursor.newRow();
|
||||
row.add(Long.valueOf(Mailbox.QUERY_ALL_INBOXES)); // MAILBOX_COLUMN_ID = 0;
|
||||
// MAILBOX_DISPLAY_NAME
|
||||
row.add(mActivity.getString(R.string.account_folder_list_summary_inbox));
|
||||
row.add(null); // MAILBOX_ACCOUNT_KEY = 2;
|
||||
row.add(Integer.valueOf(Mailbox.TYPE_INBOX)); // MAILBOX_TYPE = 3;
|
||||
row.add(Integer.valueOf(count)); // MAILBOX_UNREAD_COUNT = 4;
|
||||
// TYPE_MAIL (FAVORITES)
|
||||
count = EmailContent.count(mActivity, Message.CONTENT_URI, FAVORITE_COUNT_SELECTION, null);
|
||||
if (count > 0) {
|
||||
row = childCursor.newRow();
|
||||
row.add(Long.valueOf(Mailbox.QUERY_ALL_FAVORITES)); // MAILBOX_COLUMN_ID = 0;
|
||||
// MAILBOX_DISPLAY_NAME
|
||||
row.add(mActivity.getString(R.string.account_folder_list_summary_starred));
|
||||
row.add(null); // MAILBOX_ACCOUNT_KEY = 2;
|
||||
row.add(Integer.valueOf(Mailbox.TYPE_MAIL)); // MAILBOX_TYPE = 3;
|
||||
row.add(Integer.valueOf(count)); // MAILBOX_UNREAD_COUNT = 4;
|
||||
}
|
||||
// TYPE_DRAFTS
|
||||
count = getCountByMailboxType(mActivity, Mailbox.TYPE_DRAFTS);
|
||||
if (count > 0) {
|
||||
row = childCursor.newRow();
|
||||
row.add(Long.valueOf(Mailbox.QUERY_ALL_DRAFTS)); // MAILBOX_COLUMN_ID = 0;
|
||||
// MAILBOX_DISPLAY_NAME
|
||||
row.add(mActivity.getString(R.string.account_folder_list_summary_drafts));
|
||||
row.add(null); // MAILBOX_ACCOUNT_KEY = 2;
|
||||
row.add(Integer.valueOf(Mailbox.TYPE_DRAFTS)); // MAILBOX_TYPE = 3;
|
||||
row.add(Integer.valueOf(count)); // MAILBOX_UNREAD_COUNT = 4;
|
||||
}
|
||||
// TYPE_OUTBOX
|
||||
count = getCountByMailboxType(mActivity, Mailbox.TYPE_OUTBOX);
|
||||
if (count > 0) {
|
||||
row = childCursor.newRow();
|
||||
row.add(Long.valueOf(Mailbox.QUERY_ALL_OUTBOX)); // MAILBOX_COLUMN_ID = 0;
|
||||
// MAILBOX_DISPLAY_NAME
|
||||
row.add(mActivity.getString(R.string.account_folder_list_summary_outbox));
|
||||
row.add(null); // MAILBOX_ACCOUNT_KEY = 2;
|
||||
row.add(Integer.valueOf(Mailbox.TYPE_OUTBOX)); // MAILBOX_TYPE = 3;
|
||||
row.add(Integer.valueOf(count)); // MAILBOX_UNREAD_COUNT = 4;
|
||||
}
|
||||
return childCursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Async task to handle the accounts query outside of the UI thread
|
||||
*/
|
||||
private class LoadAccountsTask extends AsyncTask<Void, Void, Object[]> {
|
||||
@Override
|
||||
protected Object[] doInBackground(Void... params) {
|
||||
// Create the summaries cursor
|
||||
Cursor c1 = null;
|
||||
Cursor c2 = null;
|
||||
Long defaultAccount = null;
|
||||
if (!isCancelled()) {
|
||||
// Create the summaries cursor
|
||||
c1 = getSummaryChildCursor();
|
||||
}
|
||||
|
||||
if (!isCancelled()) {
|
||||
// TODO use a custom projection and don't have to sample all of these columns
|
||||
c2 = mActivity.getContentResolver().query(
|
||||
EmailContent.Account.CONTENT_URI,
|
||||
EmailContent.Account.CONTENT_PROJECTION, null, null, null);
|
||||
}
|
||||
|
||||
if (!isCancelled()) {
|
||||
defaultAccount = Account.getDefaultAccountId(mActivity);
|
||||
}
|
||||
|
||||
if (isCancelled()) {
|
||||
if (c1 != null) c1.close();
|
||||
if (c2 != null) c2.close();
|
||||
return null;
|
||||
}
|
||||
return new Object[] { c1, c2 , defaultAccount};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Object[] params) {
|
||||
if (isCancelled() || params == null) {
|
||||
if (params != null) {
|
||||
Cursor c1 = (Cursor)params[0];
|
||||
if (c1 != null) {
|
||||
c1.close();
|
||||
}
|
||||
Cursor c2 = (Cursor)params[1];
|
||||
if (c2 != null) {
|
||||
c2.close();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Before writing a new list adapter into the listview, we need to
|
||||
// shut down the old one (if any).
|
||||
ListAdapter oldAdapter = mListView.getAdapter();
|
||||
if (oldAdapter != null && oldAdapter instanceof CursorAdapter) {
|
||||
((CursorAdapter)oldAdapter).changeCursor(null);
|
||||
}
|
||||
// Now create a new list adapter and install it
|
||||
mListAdapter = AccountsAdapter.getInstance((Cursor)params[0], (Cursor)params[1],
|
||||
mActivity, (Long)params[2], AccountFolderListFragment.this);
|
||||
setListAdapter(mListAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller results listener. We wrap it with {@link ControllerResultUiThreadWrapper},
|
||||
* so all methods are called on the UI thread.
|
||||
*/
|
||||
private class ControllerResults extends Controller.Result {
|
||||
@Override
|
||||
public void updateMailboxCallback(MessagingException result, long accountKey,
|
||||
long mailboxKey, int progress, int numNewMessages,
|
||||
ArrayList<Long> addedMessages) {
|
||||
if (progress == 100) {
|
||||
updateAccounts();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMailCallback(MessagingException result, long accountId, long messageId,
|
||||
int progress) {
|
||||
if (progress == 100) {
|
||||
updateAccounts();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAccountCallback(long accountId) {
|
||||
updateAccounts();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.activity;
|
||||
|
||||
import com.android.email.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
/**
|
||||
* This custom View is the list item for the AccountFolderList activity, and serves two purposes:
|
||||
* 1. It's a container to store row metadata
|
||||
* 2. It handles internal clicks so we can create virtual "buttons" in the list
|
||||
*/
|
||||
public class AccountFolderListItem extends LinearLayout {
|
||||
|
||||
public long mAccountId;
|
||||
|
||||
private AccountsAdapter mAdapter;
|
||||
|
||||
private boolean mHasFolderButton;
|
||||
private boolean mDownEvent;
|
||||
private boolean mCachedViewPositions;
|
||||
private int mFolderLeft;
|
||||
|
||||
private final static float FOLDER_PAD = 5.0F;
|
||||
|
||||
public AccountFolderListItem(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public AccountFolderListItem(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the adapter at bindView() time
|
||||
*
|
||||
* @param adapter the adapter that creates this view
|
||||
*/
|
||||
public void bindViewInit(AccountsAdapter adapter, boolean hasFolderButton) {
|
||||
mAdapter = adapter;
|
||||
mCachedViewPositions = false;
|
||||
mHasFolderButton = hasFolderButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding this method allows us to "catch" clicks in the checkbox or star
|
||||
* and process them accordingly.
|
||||
*/
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (mAdapter.isOnDeletingAccountView(mAccountId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Short-circuit all of this for list items w/o folder buttons
|
||||
if (!mHasFolderButton) {
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
boolean handled = false;
|
||||
int touchX = (int) event.getX();
|
||||
|
||||
if (!mCachedViewPositions) {
|
||||
float paddingScale = getContext().getResources().getDisplayMetrics().density;
|
||||
int folderPadding = (int) ((FOLDER_PAD * paddingScale) + 0.5);
|
||||
mFolderLeft = findViewById(R.id.folder_button).getLeft() - folderPadding;
|
||||
mCachedViewPositions = true;
|
||||
}
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mDownEvent = true;
|
||||
if (touchX > mFolderLeft) {
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mDownEvent = false;
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (mDownEvent) {
|
||||
if (touchX > mFolderLeft) {
|
||||
mAdapter.onClickFolder(this);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
postInvalidate();
|
||||
} else {
|
||||
handled = super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
}
|
|
@ -1,381 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.activity;
|
||||
|
||||
import com.android.email.FolderProperties;
|
||||
import com.android.email.R;
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.Account;
|
||||
import com.android.emailcommon.provider.EmailContent.Mailbox;
|
||||
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.MergeCursor;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CursorAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Adapter that presents a combined list of smart mailboxes (e.g. combined inbox, all drafts, etc),
|
||||
* a non-selectable separator, and the list of accounts.
|
||||
*/
|
||||
public class AccountsAdapter extends CursorAdapter {
|
||||
|
||||
/**
|
||||
* Reduced mailbox projection used by AccountsAdapter
|
||||
*/
|
||||
public final static String[] MAILBOX_PROJECTION = new String[] {
|
||||
EmailContent.RECORD_ID, MailboxColumns.DISPLAY_NAME,
|
||||
MailboxColumns.ACCOUNT_KEY, MailboxColumns.TYPE,
|
||||
MailboxColumns.UNREAD_COUNT,
|
||||
MailboxColumns.FLAG_VISIBLE, MailboxColumns.FLAGS
|
||||
};
|
||||
public final static int MAILBOX_COLUMN_ID = 0;
|
||||
public final static int MAILBOX_DISPLAY_NAME = 1;
|
||||
public final static int MAILBOX_ACCOUNT_KEY = 2;
|
||||
public final static int MAILBOX_TYPE = 3;
|
||||
public final static int MAILBOX_UNREAD_COUNT = 4;
|
||||
public final static int MAILBOX_FLAG_VISIBLE = 5;
|
||||
public final static int MAILBOX_FLAGS = 6;
|
||||
|
||||
private static final String[] MAILBOX_UNREAD_COUNT_PROJECTION = new String [] {
|
||||
MailboxColumns.UNREAD_COUNT
|
||||
};
|
||||
private static final int MAILBOX_UNREAD_COUNT_COLUMN_UNREAD_COUNT = 0;
|
||||
|
||||
private static final String MAILBOX_INBOX_SELECTION =
|
||||
MailboxColumns.ACCOUNT_KEY + " =?" + " AND " + MailboxColumns.TYPE +" = "
|
||||
+ Mailbox.TYPE_INBOX;
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
private final int mMailboxesCount;
|
||||
private final int mSeparatorPosition;
|
||||
private final long mDefaultAccountId;
|
||||
private final ArrayList<Long> mOnDeletingAccounts = new ArrayList<Long>();
|
||||
private Callback mCallback;
|
||||
|
||||
public static AccountsAdapter getInstance(Cursor mailboxesCursor, Cursor accountsCursor,
|
||||
Context context, long defaultAccountId, Callback callback) {
|
||||
Cursor[] cursors = new Cursor[] { mailboxesCursor, accountsCursor };
|
||||
Cursor mc = new MergeCursor(cursors);
|
||||
return new AccountsAdapter(mc, context, mailboxesCursor.getCount(), defaultAccountId,
|
||||
callback);
|
||||
}
|
||||
|
||||
private AccountsAdapter(Cursor c, Context context, int mailboxesCount, long defaultAccountId,
|
||||
Callback callback) {
|
||||
super(context, c, true);
|
||||
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
mMailboxesCount = mailboxesCount;
|
||||
mSeparatorPosition = mailboxesCount;
|
||||
mDefaultAccountId = defaultAccountId;
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* When changeCursor(null) is called, drop reference(s) to make sure we don't leak the activity
|
||||
*/
|
||||
@Override
|
||||
public void changeCursor(Cursor cursor) {
|
||||
super.changeCursor(cursor);
|
||||
if (cursor == null) {
|
||||
mCallback = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface used to report clicks other than the basic list item click or longpress.
|
||||
*/
|
||||
public interface Callback {
|
||||
/**
|
||||
* Callback for clicks on the "folder" icon (to open MailboxList)
|
||||
*/
|
||||
public void onClickAccountFolders(long accountId);
|
||||
}
|
||||
|
||||
public boolean isMailbox(int position) {
|
||||
return position < mMailboxesCount;
|
||||
}
|
||||
|
||||
public boolean isAccount(int position) {
|
||||
return position > mMailboxesCount;
|
||||
}
|
||||
|
||||
public void addOnDeletingAccount(long accountId) {
|
||||
mOnDeletingAccounts.add(accountId);
|
||||
}
|
||||
|
||||
public boolean isOnDeletingAccountView(long accountId) {
|
||||
return mOnDeletingAccounts.contains(accountId);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is an entry point called by the list item for clicks in the folder "button"
|
||||
*
|
||||
* @param itemView the item in which the click occurred
|
||||
*/
|
||||
public void onClickFolder(AccountFolderListItem itemView) {
|
||||
if (mCallback != null) {
|
||||
mCallback.onClickAccountFolders(itemView.mAccountId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
if (cursor.getPosition() < mMailboxesCount) {
|
||||
bindMailboxItem(view, context, cursor, false);
|
||||
} else {
|
||||
bindAccountItem(view, context, cursor, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void bindMailboxItem(View view, Context context, Cursor cursor, boolean isLastChild)
|
||||
{
|
||||
// Reset the view (in case it was recycled) and prepare for binding
|
||||
AccountFolderListItem itemView = (AccountFolderListItem) view;
|
||||
itemView.bindViewInit(this, false);
|
||||
|
||||
// Invisible (not "gone") to maintain spacing
|
||||
view.findViewById(R.id.chip).setVisibility(View.INVISIBLE);
|
||||
|
||||
String text = cursor.getString(MAILBOX_DISPLAY_NAME);
|
||||
if (text != null) {
|
||||
TextView nameView = (TextView) view.findViewById(R.id.name);
|
||||
nameView.setText(text);
|
||||
}
|
||||
|
||||
// TODO get/track live folder status
|
||||
text = null;
|
||||
TextView statusView = (TextView) view.findViewById(R.id.status);
|
||||
if (text != null) {
|
||||
statusView.setText(text);
|
||||
statusView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
statusView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
int count = -1;
|
||||
text = cursor.getString(MAILBOX_UNREAD_COUNT);
|
||||
if (text != null) {
|
||||
count = Integer.valueOf(text);
|
||||
}
|
||||
TextView unreadCountView = (TextView) view.findViewById(R.id.new_message_count);
|
||||
TextView allCountView = (TextView) view.findViewById(R.id.all_message_count);
|
||||
int id = cursor.getInt(MAILBOX_COLUMN_ID);
|
||||
// If the unread count is zero, not to show countView.
|
||||
if (count > 0) {
|
||||
if (id == Mailbox.QUERY_ALL_FAVORITES
|
||||
|| id == Mailbox.QUERY_ALL_DRAFTS
|
||||
|| id == Mailbox.QUERY_ALL_OUTBOX) {
|
||||
unreadCountView.setVisibility(View.GONE);
|
||||
allCountView.setVisibility(View.VISIBLE);
|
||||
allCountView.setText(text);
|
||||
} else {
|
||||
allCountView.setVisibility(View.GONE);
|
||||
unreadCountView.setVisibility(View.VISIBLE);
|
||||
unreadCountView.setText(text);
|
||||
}
|
||||
} else {
|
||||
allCountView.setVisibility(View.GONE);
|
||||
unreadCountView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
view.findViewById(R.id.folder_button).setVisibility(View.GONE);
|
||||
view.findViewById(R.id.folder_separator).setVisibility(View.GONE);
|
||||
view.findViewById(R.id.default_sender).setVisibility(View.GONE);
|
||||
view.findViewById(R.id.folder_icon).setVisibility(View.VISIBLE);
|
||||
((ImageView)view.findViewById(R.id.folder_icon)).setImageDrawable(
|
||||
FolderProperties.getInstance(context).getSummaryMailboxIconIds(id));
|
||||
}
|
||||
|
||||
private void bindAccountItem(View view, Context context, Cursor cursor, boolean isExpanded)
|
||||
{
|
||||
// Reset the view (in case it was recycled) and prepare for binding
|
||||
AccountFolderListItem itemView = (AccountFolderListItem) view;
|
||||
itemView.bindViewInit(this, true);
|
||||
itemView.mAccountId = cursor.getLong(Account.CONTENT_ID_COLUMN);
|
||||
|
||||
long accountId = cursor.getLong(Account.CONTENT_ID_COLUMN);
|
||||
|
||||
// No color chip for now. TODO Revisit for phone UI
|
||||
view.findViewById(R.id.chip).setVisibility(View.GONE);
|
||||
|
||||
String text = cursor.getString(Account.CONTENT_DISPLAY_NAME_COLUMN);
|
||||
if (text != null) {
|
||||
TextView descriptionView = (TextView) view.findViewById(R.id.name);
|
||||
descriptionView.setText(text);
|
||||
}
|
||||
|
||||
text = cursor.getString(Account.CONTENT_EMAIL_ADDRESS_COLUMN);
|
||||
if (text != null) {
|
||||
TextView emailView = (TextView) view.findViewById(R.id.status);
|
||||
emailView.setText(text);
|
||||
emailView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
// TODO: We should not be doing a query inside bindAccountItem
|
||||
int unreadMessageCount = 0;
|
||||
Cursor c = context.getContentResolver().query(Mailbox.CONTENT_URI,
|
||||
MAILBOX_UNREAD_COUNT_PROJECTION,
|
||||
MAILBOX_INBOX_SELECTION,
|
||||
new String[] { String.valueOf(accountId) }, null);
|
||||
|
||||
try {
|
||||
if (c.moveToFirst()) {
|
||||
String count = c.getString(MAILBOX_UNREAD_COUNT_COLUMN_UNREAD_COUNT);
|
||||
if (count != null) {
|
||||
unreadMessageCount = Integer.valueOf(count);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
|
||||
view.findViewById(R.id.all_message_count).setVisibility(View.GONE);
|
||||
TextView unreadCountView = (TextView) view.findViewById(R.id.new_message_count);
|
||||
if (unreadMessageCount > 0) {
|
||||
unreadCountView.setText(String.valueOf(unreadMessageCount));
|
||||
unreadCountView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
unreadCountView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
view.findViewById(R.id.folder_icon).setVisibility(View.GONE);
|
||||
view.findViewById(R.id.folder_button).setVisibility(View.VISIBLE);
|
||||
view.findViewById(R.id.folder_separator).setVisibility(View.VISIBLE);
|
||||
if (accountId == mDefaultAccountId) {
|
||||
view.findViewById(R.id.default_sender).setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
view.findViewById(R.id.default_sender).setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
return mInflater.inflate(R.layout.account_folder_list_item, parent, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* The following series of overrides insert the "Accounts" separator
|
||||
*/
|
||||
|
||||
/**
|
||||
* Prevents the separator view from recycling into the other views
|
||||
*/
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (position == mSeparatorPosition) {
|
||||
return IGNORE_ITEM_VIEW_TYPE;
|
||||
}
|
||||
return super.getItemViewType(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the separator view when required, and fudges the cursor for other views
|
||||
*/
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
// The base class's getView() checks for mDataValid at the beginning, but we don't have
|
||||
// to do that, because if the cursor is invalid getCount() returns 0, in which case this
|
||||
// method wouldn't get called.
|
||||
|
||||
// Handle the separator here - create & bind
|
||||
if (position == mSeparatorPosition) {
|
||||
TextView view;
|
||||
view = (TextView) mInflater.inflate(R.layout.list_separator, parent, false);
|
||||
view.setText(R.string.account_folder_list_separator_accounts);
|
||||
return view;
|
||||
}
|
||||
return super.getView(getRealPosition(position), convertView, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces navigation to skip over the separator
|
||||
*/
|
||||
@Override
|
||||
public boolean areAllItemsEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces navigation to skip over the separator
|
||||
*/
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
if (position == mSeparatorPosition) {
|
||||
return false;
|
||||
} else if (isAccount(position)) {
|
||||
Long id = ((MergeCursor)getItem(position)).getLong(Account.CONTENT_ID_COLUMN);
|
||||
return !isOnDeletingAccountView(id);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts list count to include separator
|
||||
*/
|
||||
@Override
|
||||
public int getCount() {
|
||||
int count = super.getCount();
|
||||
if (count > 0 && (mSeparatorPosition != ListView.INVALID_POSITION)) {
|
||||
// Increment for separator, if we have anything to show.
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts list position to cursor position
|
||||
*/
|
||||
private int getRealPosition(int pos) {
|
||||
if (mSeparatorPosition == ListView.INVALID_POSITION) {
|
||||
// No separator, identity map
|
||||
return pos;
|
||||
} else if (pos <= mSeparatorPosition) {
|
||||
// Before or at the separator, identity map
|
||||
return pos;
|
||||
} else {
|
||||
// After the separator, remove 1 from the pos to get the real underlying pos
|
||||
return pos - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item using external position numbering (no separator)
|
||||
*/
|
||||
@Override
|
||||
public Object getItem(int pos) {
|
||||
return super.getItem(getRealPosition(pos));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item id using external position numbering (no separator)
|
||||
*/
|
||||
@Override
|
||||
public long getItemId(int pos) {
|
||||
return super.getItemId(getRealPosition(pos));
|
||||
}
|
||||
}
|
||||
|
|
@ -134,17 +134,4 @@ public final class ActivityHelper {
|
|||
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateRefreshMenuIcon(MenuItem item, boolean show, boolean animate) {
|
||||
if (show) {
|
||||
item.setVisible(true);
|
||||
if (animate) {
|
||||
item.setActionView(R.layout.action_bar_indeterminate_progress);
|
||||
} else {
|
||||
item.setActionView(null);
|
||||
}
|
||||
} else {
|
||||
item.setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import com.android.email.Controller;
|
|||
import com.android.email.ControllerResultUiThreadWrapper;
|
||||
import com.android.email.Email;
|
||||
import com.android.email.MessagingExceptionStrings;
|
||||
import com.android.email.NotificationController;
|
||||
import com.android.email.R;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.mail.MessagingException;
|
||||
|
|
|
@ -1,331 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.activity;
|
||||
|
||||
import com.android.email.Controller;
|
||||
import com.android.email.ControllerResultUiThreadWrapper;
|
||||
import com.android.email.Email;
|
||||
import com.android.email.MessagingExceptionStrings;
|
||||
import com.android.email.R;
|
||||
import com.android.email.RefreshManager;
|
||||
import com.android.email.activity.setup.AccountSettingsXL;
|
||||
import com.android.emailcommon.mail.MessagingException;
|
||||
import com.android.emailcommon.provider.EmailContent.Account;
|
||||
import com.android.emailcommon.provider.EmailContent.AccountColumns;
|
||||
import com.android.emailcommon.utility.Utility;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.app.Activity;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.TextView;
|
||||
|
||||
// TODO: This has a lot in common with MessageList --should we merge them somehow?
|
||||
// But maybe we'll need to move to a single activity style anyway -- let's not worry about it too
|
||||
// much for now. We might even completely ditch this activity and switch to a dialog.
|
||||
public class MailboxList extends Activity implements MailboxListFragment.Callback {
|
||||
|
||||
// Intent extras (internal to this activity)
|
||||
private static final String EXTRA_ACCOUNT_ID = "com.android.email.activity._ACCOUNT_ID";
|
||||
|
||||
// UI support
|
||||
private ActionBar mActionBar;
|
||||
private TextView mErrorBanner;
|
||||
private MailboxListFragment mListFragment;
|
||||
|
||||
private Controller.Result mControllerCallback;
|
||||
|
||||
// DB access
|
||||
private long mAccountId;
|
||||
private AsyncTask<Void, Void, String[]> mLoadAccountNameTask;
|
||||
|
||||
/**
|
||||
* Open a specific account.
|
||||
*
|
||||
* @param context
|
||||
* @param accountId the account to view
|
||||
*/
|
||||
public static void actionHandleAccount(Context context, long accountId) {
|
||||
Intent intent = new Intent(context, MailboxList.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
intent.putExtra(EXTRA_ACCOUNT_ID, accountId);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
ActivityHelper.debugSetWindowFlags(this);
|
||||
|
||||
mAccountId = getIntent().getLongExtra(EXTRA_ACCOUNT_ID, -1);
|
||||
if (mAccountId == -1) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||
setContentView(R.layout.mailbox_list);
|
||||
|
||||
mControllerCallback = new ControllerResultUiThreadWrapper<ControllerResults>(
|
||||
new Handler(), new ControllerResults());
|
||||
mActionBar = getActionBar();
|
||||
mErrorBanner = (TextView) findViewById(R.id.connection_error_text);
|
||||
mListFragment = (MailboxListFragment) getFragmentManager()
|
||||
.findFragmentById(R.id.mailbox_list_fragment);
|
||||
|
||||
mActionBar.setTitle(R.string.mailbox_list_title);
|
||||
mListFragment.setCallback(this);
|
||||
mListFragment.openMailboxes(mAccountId, -1);
|
||||
|
||||
// Halt the progress indicator (we'll display it later when needed)
|
||||
setProgressBarIndeterminate(true);
|
||||
setProgressBarIndeterminateVisibility(false);
|
||||
|
||||
// Go to the database for the account name
|
||||
mLoadAccountNameTask = new AsyncTask<Void, Void, String[]>() {
|
||||
@Override
|
||||
protected String[] doInBackground(Void... params) {
|
||||
String accountName = null;
|
||||
Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, mAccountId);
|
||||
Cursor c = MailboxList.this.getContentResolver().query(
|
||||
uri, new String[] { AccountColumns.DISPLAY_NAME }, null, null, null);
|
||||
try {
|
||||
if (c.moveToFirst()) {
|
||||
accountName = c.getString(0);
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
return new String[] { accountName };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String[] result) {
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
final String accountName = (String) result[0];
|
||||
// accountName is null if account name can't be retrieved or query exception
|
||||
if (accountName == null) {
|
||||
// something is wrong with this account
|
||||
finish();
|
||||
}
|
||||
mActionBar.setTitle(R.string.mailbox_list_title);
|
||||
mActionBar.setSubtitle(accountName);
|
||||
}
|
||||
|
||||
}.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
Controller.getInstance(getApplication()).removeResultCallback(mControllerCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Controller.getInstance(getApplication()).addResultCallback(mControllerCallback);
|
||||
|
||||
// Exit immediately if the accounts list has changed (e.g. externally deleted)
|
||||
if (Email.getNotifyUiAccountsChanged()) {
|
||||
Welcome.actionStart(this);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
Utility.cancelTaskInterrupt(mLoadAccountNameTask);
|
||||
mLoadAccountNameTask = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.mailbox_list_option, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
onAccounts();
|
||||
return true;
|
||||
case R.id.refresh:
|
||||
onRefresh();
|
||||
return true;
|
||||
case R.id.compose:
|
||||
onCompose();
|
||||
return true;
|
||||
case R.id.account_settings:
|
||||
onEditAccount();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements MailboxFragment.Callback
|
||||
*/
|
||||
@Override
|
||||
public void onMailboxSelected(long accountId, long mailboxId, boolean navigate,
|
||||
boolean dragDrop) {
|
||||
// TODO handle folder navigation on the phone. when will we actually show the messages?
|
||||
onOpenMailbox(mailboxId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements MailboxFragment.Callback
|
||||
*/
|
||||
@Override
|
||||
public void onAccountSelected(long accountId) {
|
||||
// Only used on the Combined view, which isn't used on the phone UI.
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements MailboxFragment.Callback
|
||||
*/
|
||||
@Override
|
||||
public void onCurrentMailboxUpdated(long mailboxId, String mailboxName, int unreadCount) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the mailbox list
|
||||
*/
|
||||
private void onRefresh() {
|
||||
Controller controller = Controller.getInstance(getApplication());
|
||||
showProgressIcon(true);
|
||||
RefreshManager.getInstance(this).refreshMailboxList(mAccountId);
|
||||
}
|
||||
|
||||
private void onAccounts() {
|
||||
AccountFolderList.actionShowAccounts(this);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void onEditAccount() {
|
||||
AccountSettingsXL.actionSettings(this, mAccountId);
|
||||
}
|
||||
|
||||
private void onOpenMailbox(long mailboxId) {
|
||||
MessageList.actionHandleMailbox(this, mailboxId);
|
||||
}
|
||||
|
||||
private void onCompose() {
|
||||
MessageCompose.actionCompose(this, mAccountId);
|
||||
}
|
||||
|
||||
private void showProgressIcon(boolean show) {
|
||||
setProgressBarIndeterminateVisibility(show);
|
||||
}
|
||||
|
||||
private void showErrorBanner(String message) {
|
||||
boolean isVisible = mErrorBanner.getVisibility() == View.VISIBLE;
|
||||
if (message != null) {
|
||||
mErrorBanner.setText(message);
|
||||
if (!isVisible) {
|
||||
mErrorBanner.setVisibility(View.VISIBLE);
|
||||
mErrorBanner.startAnimation(
|
||||
AnimationUtils.loadAnimation(
|
||||
MailboxList.this, R.anim.header_appear));
|
||||
}
|
||||
} else {
|
||||
if (isVisible) {
|
||||
mErrorBanner.setVisibility(View.GONE);
|
||||
mErrorBanner.startAnimation(
|
||||
AnimationUtils.loadAnimation(
|
||||
MailboxList.this, R.anim.header_disappear));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller results listener. We wrap it with {@link ControllerResultUiThreadWrapper},
|
||||
* so all methods are called on the UI thread.
|
||||
*/
|
||||
private class ControllerResults extends Controller.Result {
|
||||
|
||||
@Override
|
||||
public void updateMailboxListCallback(MessagingException result, long accountKey,
|
||||
int progress) {
|
||||
if (accountKey == mAccountId) {
|
||||
updateBanner(result, progress);
|
||||
updateProgress(result, progress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMailboxCallback(MessagingException result, long accountKey,
|
||||
long mailboxKey, int progress, int numNewMessages, ArrayList<Long> addedMessages) {
|
||||
if (accountKey == mAccountId) {
|
||||
updateBanner(result, progress);
|
||||
updateProgress(result, progress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMailCallback(MessagingException result, long accountId, long messageId,
|
||||
int progress) {
|
||||
if (accountId == mAccountId) {
|
||||
updateBanner(result, progress);
|
||||
updateProgress(result, progress);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProgress(MessagingException result, int progress) {
|
||||
showProgressIcon(result == null && progress < 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or hide the connection error banner, and convert the various MessagingException
|
||||
* variants into localizable text. There is hysteresis in the show/hide logic: Once shown,
|
||||
* the banner will remain visible until some progress is made on the connection. The
|
||||
* goal is to keep it from flickering during retries in a bad connection state.
|
||||
*
|
||||
* @param result
|
||||
* @param progress
|
||||
*/
|
||||
private void updateBanner(MessagingException result, int progress) {
|
||||
if (result != null) {
|
||||
showErrorBanner(
|
||||
MessagingExceptionStrings.getErrorString(MailboxList.this, result));
|
||||
} else if (progress > 0) {
|
||||
showErrorBanner(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,354 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.activity;
|
||||
|
||||
import com.android.email.Email;
|
||||
import com.android.email.R;
|
||||
import com.android.email.RefreshManager;
|
||||
import com.android.email.activity.setup.AccountSecurity;
|
||||
import com.android.email.activity.setup.AccountSettingsXL;
|
||||
import com.android.emailcommon.provider.EmailContent.Account;
|
||||
import com.android.emailcommon.provider.EmailContent.Mailbox;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class MessageList extends Activity implements MessageListFragment.Callback {
|
||||
// Intent extras (internal to this activity)
|
||||
private static final String EXTRA_ACCOUNT_ID = "com.android.email.activity._ACCOUNT_ID";
|
||||
private static final String EXTRA_MAILBOX_TYPE = "com.android.email.activity.MAILBOX_TYPE";
|
||||
private static final String EXTRA_MAILBOX_ID = "com.android.email.activity.MAILBOX_ID";
|
||||
|
||||
private static final int REQUEST_SECURITY = 0;
|
||||
|
||||
// UI support
|
||||
private MessageListFragment mListFragment;
|
||||
private TextView mErrorBanner;
|
||||
|
||||
private RefreshManager mRefreshManager;
|
||||
private final RefreshListener mRefreshListener = new RefreshListener();
|
||||
|
||||
private MailboxFinder mMailboxFinder;
|
||||
private final MailboxFinderCallback mMailboxFinderCallback = new MailboxFinderCallback();
|
||||
|
||||
/* package */ MessageListFragment getListFragmentForTest() {
|
||||
return mListFragment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a specific mailbox.
|
||||
*
|
||||
* TODO This should just shortcut to a more generic version that can accept a list of
|
||||
* accounts/mailboxes (e.g. merged inboxes).
|
||||
*
|
||||
* @param context
|
||||
* @param mailboxType mailbox key
|
||||
*/
|
||||
public static void actionHandleMailbox(Context context, long mailboxType) {
|
||||
context.startActivity(createIntent(context, -1, mailboxType, -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a specific mailbox by account & type
|
||||
*
|
||||
* @param context The caller's context (for generating an intent)
|
||||
* @param accountId The account to open
|
||||
* @param mailboxType the type of mailbox to open (e.g. @see EmailContent.Mailbox.TYPE_INBOX)
|
||||
*/
|
||||
public static void actionHandleAccount(Context context, long accountId, int mailboxType) {
|
||||
context.startActivity(createIntent(context, accountId, -1, mailboxType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an intent to open a specific mailbox by account & type.
|
||||
*
|
||||
* @param context The caller's context (for generating an intent)
|
||||
* @param accountId The account to open, or -1
|
||||
* @param mailboxId the ID of the mailbox to open, or -1
|
||||
* @param mailboxType the type of mailbox to open (e.g. @see Mailbox.TYPE_INBOX) or -1
|
||||
*/
|
||||
public static Intent createIntent(Context context, long accountId, long mailboxId,
|
||||
int mailboxType) {
|
||||
Intent intent = new Intent(context, MessageList.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
if (accountId != -1) intent.putExtra(EXTRA_ACCOUNT_ID, accountId);
|
||||
if (mailboxId != -1) intent.putExtra(EXTRA_MAILBOX_ID, mailboxId);
|
||||
if (mailboxType != -1) intent.putExtra(EXTRA_MAILBOX_TYPE, mailboxType);
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
ActivityHelper.debugSetWindowFlags(this);
|
||||
setContentView(R.layout.message_list);
|
||||
|
||||
mRefreshManager = RefreshManager.getInstance(this);
|
||||
mRefreshManager.registerListener(mRefreshListener);
|
||||
mListFragment = (MessageListFragment) getFragmentManager()
|
||||
.findFragmentById(R.id.message_list_fragment);
|
||||
mErrorBanner = (TextView) findViewById(R.id.connection_error_text);
|
||||
|
||||
mListFragment.setCallback(this);
|
||||
|
||||
// Show the appropriate account/mailbox specified by an {@link Intent}.
|
||||
selectAccountAndMailbox(getIntent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the appropriate account/mailbox specified by an {@link Intent}.
|
||||
*/
|
||||
private void selectAccountAndMailbox(Intent intent) {
|
||||
long mailboxId = intent.getLongExtra(EXTRA_MAILBOX_ID, -1);
|
||||
if (mailboxId != -1) {
|
||||
mListFragment.openMailbox(mailboxId);
|
||||
} else {
|
||||
int mailboxType = intent.getIntExtra(EXTRA_MAILBOX_TYPE, Mailbox.TYPE_INBOX);
|
||||
Uri uri = intent.getData();
|
||||
// TODO Possible ANR. getAccountIdFromShortcutSafeUri accesses DB.
|
||||
long accountId = (uri == null) ? -1
|
||||
: Account.getAccountIdFromShortcutSafeUri(this, uri);
|
||||
if (accountId == -1) {
|
||||
accountId = intent.getLongExtra(EXTRA_ACCOUNT_ID, -1);
|
||||
}
|
||||
if (accountId == -1) {
|
||||
launchWelcomeAndFinish();
|
||||
return;
|
||||
}
|
||||
mMailboxFinder = new MailboxFinder(this, accountId, mailboxType,
|
||||
mMailboxFinderCallback);
|
||||
mMailboxFinder.startLookup();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
// Exit immediately if the accounts list has changed (e.g. externally deleted)
|
||||
if (Email.getNotifyUiAccountsChanged()) {
|
||||
Welcome.actionStart(this);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (mMailboxFinder != null) {
|
||||
mMailboxFinder.cancel();
|
||||
mMailboxFinder = null;
|
||||
}
|
||||
mRefreshManager.unregisterListener(mRefreshListener);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
||||
private void launchWelcomeAndFinish() {
|
||||
Welcome.actionStart(this);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListLoaded() {
|
||||
// Now we know if the mailbox is refreshable
|
||||
updateProgressIcon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the list fragment can't find mailbox/account.
|
||||
*/
|
||||
@Override
|
||||
public void onMailboxNotFound() {
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageOpen(long messageId, long messageMailboxId, long listMailboxId, int type) {
|
||||
if (type == MessageListFragment.Callback.TYPE_DRAFT) {
|
||||
MessageCompose.actionEditDraft(this, messageId);
|
||||
} else {
|
||||
// WARNING: here we pass "listMailboxId", which can be the negative id of
|
||||
// a combined mailbox, instead of the mailboxId of the particular message that
|
||||
// is opened. This is to support the next/prev buttons on the message view
|
||||
// properly even for combined mailboxes.
|
||||
MessageView.actionView(this, messageId, listMailboxId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnterSelectionMode(boolean enter) {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onAdvancingOpAccepted(Set<Long> affectedMessages) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.message_list_option, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
// this method can be called in the very early stage of the activity lifecycle, where
|
||||
// mListFragment isn't ready yet.
|
||||
boolean show = (mListFragment != null) && mListFragment.isRefreshable();
|
||||
boolean animate = (mListFragment != null) && mRefreshManager.isMessageListRefreshing(
|
||||
mListFragment.getMailboxId());
|
||||
ActivityHelper.updateRefreshMenuIcon(menu.findItem(R.id.refresh), show, animate);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.refresh:
|
||||
mListFragment.onRefresh(true);
|
||||
return true;
|
||||
case R.id.folders:
|
||||
onFolders();
|
||||
return true;
|
||||
case R.id.accounts:
|
||||
onAccounts();
|
||||
return true;
|
||||
case R.id.compose:
|
||||
onCompose();
|
||||
return true;
|
||||
case R.id.account_settings:
|
||||
onEditAccount();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void onFolders() {
|
||||
long accountId = mListFragment.getAccountId();
|
||||
// accountId will be -1 when a) mailbox is still loading, or for magic mailboxes.
|
||||
if (accountId != -1) {
|
||||
MailboxList.actionHandleAccount(this, accountId);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void onAccounts() {
|
||||
AccountFolderList.actionShowAccounts(this);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void onCompose() {
|
||||
// Passing account = -1 is okay -- the default account will be used.
|
||||
MessageCompose.actionCompose(this, mListFragment.getAccountId());
|
||||
}
|
||||
|
||||
private void onEditAccount() {
|
||||
// Passing account = -1 is okay
|
||||
AccountSettingsXL.actionSettings(this, mListFragment.getAccountId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the eventual result from the security update activity
|
||||
*
|
||||
* Note, this is extremely coarse, and it simply returns the user to the Accounts list.
|
||||
* Anything more requires refactoring of this Activity.
|
||||
*/
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_SECURITY:
|
||||
onAccounts();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProgressIcon() {
|
||||
invalidateOptionsMenu(); // animate/stop refreshing icon
|
||||
}
|
||||
|
||||
private void showErrorBanner(String message) {
|
||||
boolean isVisible = mErrorBanner.getVisibility() == View.VISIBLE;
|
||||
if (!TextUtils.isEmpty(message)) {
|
||||
mErrorBanner.setText(message);
|
||||
if (!isVisible) {
|
||||
mErrorBanner.setVisibility(View.VISIBLE);
|
||||
mErrorBanner.startAnimation(
|
||||
AnimationUtils.loadAnimation(
|
||||
MessageList.this, R.anim.header_appear));
|
||||
}
|
||||
} else {
|
||||
if (isVisible) {
|
||||
mErrorBanner.setVisibility(View.GONE);
|
||||
mErrorBanner.startAnimation(
|
||||
AnimationUtils.loadAnimation(
|
||||
MessageList.this, R.anim.header_disappear));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class RefreshListener implements RefreshManager.Listener {
|
||||
@Override
|
||||
public void onMessagingError(long accountId, long mailboxId, String message) {
|
||||
updateProgressIcon();
|
||||
showErrorBanner(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefreshStatusChanged(long accountId, long mailboxId) {
|
||||
updateProgressIcon();
|
||||
showErrorBanner(null);
|
||||
}
|
||||
}
|
||||
|
||||
private class MailboxFinderCallback implements MailboxFinder.Callback {
|
||||
@Override
|
||||
public void onMailboxFound(long accountId, long mailboxId) {
|
||||
mListFragment.openMailbox(mailboxId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccountNotFound() {
|
||||
// Let the Welcome activity show the default screen.
|
||||
launchWelcomeAndFinish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMailboxNotFound(long accountId) {
|
||||
// Let the Welcome activity show the default screen.
|
||||
launchWelcomeAndFinish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccountSecurityHold(long accountId) {
|
||||
// launch the security setup activity
|
||||
Intent i = AccountSecurity.actionUpdateSecurityIntent(
|
||||
MessageList.this, accountId, true);
|
||||
startActivityForResult(i, REQUEST_SECURITY);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1263,7 +1263,7 @@ public class MessageListFragment extends ListFragment
|
|||
mSelectionMode = mode;
|
||||
|
||||
MenuInflater inflater = getActivity().getMenuInflater();
|
||||
inflater.inflate(R.menu.message_list_selection_mode, menu);
|
||||
inflater.inflate(R.menu.message_list_fragment_cab_options, menu);
|
||||
mMarkRead = menu.findItem(R.id.mark_read);
|
||||
mMarkUnread = menu.findItem(R.id.mark_unread);
|
||||
mAddStar = menu.findItem(R.id.add_star);
|
||||
|
|
|
@ -1,374 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.activity;
|
||||
|
||||
import com.android.email.Email;
|
||||
import com.android.email.Preferences;
|
||||
import com.android.email.R;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.provider.EmailContent.Mailbox;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Activity to show (non-EML) email messages.
|
||||
*
|
||||
* This activity shows regular email messages, which are not file-based. (i.e. not *.eml or *.msg)
|
||||
*
|
||||
* See {@link MessageViewBase} for the class relation diagram.
|
||||
*/
|
||||
public class MessageView extends MessageViewBase implements View.OnClickListener,
|
||||
MessageOrderManager.Callback, MessageViewFragment.Callback {
|
||||
private static final String EXTRA_MESSAGE_ID = "com.android.email.MessageView_message_id";
|
||||
private static final String EXTRA_MAILBOX_ID = "com.android.email.MessageView_mailbox_id";
|
||||
|
||||
// for saveInstanceState()
|
||||
private static final String STATE_MESSAGE_ID = "messageId";
|
||||
|
||||
private long mMessageId;
|
||||
private long mMailboxId;
|
||||
|
||||
private MessageOrderManager mOrderManager;
|
||||
|
||||
private MessageViewFragment mFragment;
|
||||
|
||||
private View mMoveToNewer;
|
||||
private View mMoveToOlder;
|
||||
private View mReplyButton;
|
||||
private View mReplyAllButton;
|
||||
|
||||
// False when a message can't be forwarded/replied, such as trashed messages
|
||||
private boolean mReplyAndForwardEnabled;
|
||||
|
||||
/**
|
||||
* View a specific message found in the Email provider.
|
||||
* @param messageId the message to view.
|
||||
* @param mailboxId identifies the sequence of messages used for newer/older navigation.
|
||||
*/
|
||||
public static void actionView(Context context, long messageId, long mailboxId) {
|
||||
context.startActivity(getActionViewIntent(context, messageId, mailboxId));
|
||||
}
|
||||
|
||||
public static Intent getActionViewIntent(Context context, long messageId, long mailboxId) {
|
||||
if (messageId < 0) {
|
||||
throw new IllegalArgumentException("MessageView invalid messageId " + messageId);
|
||||
}
|
||||
Intent i = new Intent(context, MessageView.class);
|
||||
i.putExtra(EXTRA_MESSAGE_ID, messageId);
|
||||
i.putExtra(EXTRA_MAILBOX_ID, mailboxId);
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
return R.layout.message_view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
mFragment = (MessageViewFragment) getFragmentManager()
|
||||
.findFragmentById(R.id.message_view_fragment);
|
||||
mFragment.setCallback(this);
|
||||
|
||||
mMoveToNewer = UiUtilities.getView(this, R.id.moveToNewer);
|
||||
mMoveToOlder = UiUtilities.getView(this, R.id.moveToOlder);
|
||||
mMoveToNewer.setOnClickListener(this);
|
||||
mMoveToOlder.setOnClickListener(this);
|
||||
mReplyButton = UiUtilities.getView(this, R.id.reply);
|
||||
mReplyAllButton = UiUtilities.getView(this, R.id.reply_all);
|
||||
|
||||
initFromIntent();
|
||||
if (icicle != null) {
|
||||
mMessageId = icicle.getLong(STATE_MESSAGE_ID, mMessageId);
|
||||
}
|
||||
}
|
||||
|
||||
private void initFromIntent() {
|
||||
Intent intent = getIntent();
|
||||
mMessageId = intent.getLongExtra(EXTRA_MESSAGE_ID, -1);
|
||||
mMailboxId = intent.getLongExtra(EXTRA_MAILBOX_ID, -1);
|
||||
if (mMessageId == -1 || mMailboxId == -1) {
|
||||
Log.w(Logging.LOG_TAG, "Insufficient intent parameter. Closing...");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
enableForwardReply(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle state) {
|
||||
super.onSaveInstanceState(state);
|
||||
if (mMessageId != -1) {
|
||||
state.putLong(STATE_MESSAGE_ID, mMessageId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// Exit immediately if the accounts list has changed (e.g. externally deleted)
|
||||
if (Email.getNotifyUiAccountsChanged()) {
|
||||
Welcome.actionStart(this);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
mOrderManager = new MessageOrderManager(this, mMailboxId, this);
|
||||
messageChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
if (mOrderManager != null) {
|
||||
mOrderManager.close();
|
||||
mOrderManager = null;
|
||||
}
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
// Note the return type is a subclass of that of the super class method.
|
||||
@Override
|
||||
protected MessageViewFragment getFragment() {
|
||||
return mFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getAccountId() {
|
||||
return getFragment().getAccountId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageViewShown(int mailboxType) {
|
||||
super.onMessageViewShown(mailboxType);
|
||||
enableForwardReply(mailboxType != Mailbox.TYPE_TRASH);
|
||||
}
|
||||
|
||||
private void onDeleteMessage() {
|
||||
// the delete triggers mCursorObserver in MessageOrderManager.
|
||||
// first move to older/newer before the actual delete
|
||||
long messageIdToDelete = mMessageId;
|
||||
|
||||
boolean moved = autoAdvance();
|
||||
ActivityHelper.deleteMessage(this, messageIdToDelete);
|
||||
if (!moved) {
|
||||
// this generates a benign warning "Duplicate finish request" because
|
||||
// MessageOrderManager detects that the current message is gone, and we finish() it
|
||||
// in the onMessageNotFound() callback.
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-advances the message being shown according to the auto-advance policy set in preferences
|
||||
* @return Whether or not a new message was selected. This will return false either if there are
|
||||
* no appropriate messages to advance to, or if the preferences indicate we should not
|
||||
* auto-advance
|
||||
*/
|
||||
private boolean autoAdvance() {
|
||||
switch (Preferences.getPreferences(this).getAutoAdvanceDirection()) {
|
||||
case Preferences.AUTO_ADVANCE_NEWER:
|
||||
return moveToNewer();
|
||||
case Preferences.AUTO_ADVANCE_OLDER:
|
||||
return moveToOlder();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean moveToOlder() {
|
||||
if (mOrderManager != null && mOrderManager.moveToOlder()) {
|
||||
mMessageId = mOrderManager.getCurrentMessageId();
|
||||
messageChanged();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean moveToNewer() {
|
||||
if (mOrderManager != null && mOrderManager.moveToNewer()) {
|
||||
mMessageId = mOrderManager.getCurrentMessageId();
|
||||
messageChanged();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onClick(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.reply:
|
||||
onReply();
|
||||
break;
|
||||
case R.id.reply_all:
|
||||
onReplyAll();
|
||||
break;
|
||||
case R.id.delete:
|
||||
onDeleteMessage();
|
||||
break;
|
||||
case R.id.moveToOlder:
|
||||
moveToOlder();
|
||||
break;
|
||||
case R.id.moveToNewer:
|
||||
moveToNewer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
boolean handled = handleMenuItem(item.getItemId());
|
||||
if (!handled) {
|
||||
handled = super.onOptionsItemSelected(item);
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the core functionality of onOptionsItemSelected() but broken out and exposed
|
||||
* for testing purposes (because it's annoying to mock a MenuItem).
|
||||
*
|
||||
* @param menuItemId id that was clicked
|
||||
* @return true if handled here
|
||||
*/
|
||||
/* package */ boolean handleMenuItem(int menuItemId) {
|
||||
switch (menuItemId) {
|
||||
case R.id.delete:
|
||||
onDeleteMessage();
|
||||
break;
|
||||
case R.id.reply:
|
||||
onReply();
|
||||
break;
|
||||
case R.id.reply_all:
|
||||
onReplyAll();
|
||||
break;
|
||||
case R.id.forward:
|
||||
onForward();
|
||||
break;
|
||||
case R.id.mark_as_unread:
|
||||
getFragment().onMarkMessageAsRead(false);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageSetUnread() {
|
||||
if (!autoAdvance()) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void enableForwardReply(boolean enabled) {
|
||||
mReplyAndForwardEnabled = enabled;
|
||||
mReplyButton.setEnabled(enabled);
|
||||
mReplyAllButton.setEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.message_view_option, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
menu.findItem(R.id.forward).setEnabled(mReplyAndForwardEnabled);
|
||||
menu.findItem(R.id.reply).setEnabled(mReplyAndForwardEnabled);
|
||||
menu.findItem(R.id.reply_all).setEnabled(mReplyAndForwardEnabled);
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync the current message.
|
||||
* - Set message id to the fragment and the message order manager.
|
||||
* - Update the navigation arrows.
|
||||
*/
|
||||
private void messageChanged() {
|
||||
getFragment().openMessage(mMessageId);
|
||||
if (mOrderManager != null) {
|
||||
mOrderManager.moveTo(mMessageId);
|
||||
}
|
||||
updateNavigationArrows();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the arrows based on the current position of the older/newer cursor.
|
||||
*/
|
||||
private void updateNavigationArrows() {
|
||||
mMoveToNewer.setEnabled((mOrderManager != null) && mOrderManager.canMoveToNewer());
|
||||
mMoveToOlder.setEnabled((mOrderManager != null) && mOrderManager.canMoveToOlder());
|
||||
}
|
||||
|
||||
/** Implements {@link MessageOrderManager.Callback#onMessageNotFound()}. */
|
||||
// TODO Name too generic. Rename this.
|
||||
@Override
|
||||
public void onMessageNotFound() {
|
||||
finish();
|
||||
}
|
||||
|
||||
/** Implements {@link MessageOrderManager.Callback#onMessagesChanged()}. */
|
||||
// TODO Name too generic. Rename this.
|
||||
@Override
|
||||
public void onMessagesChanged() {
|
||||
updateNavigationArrows();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRespondedToInvite(int response) {
|
||||
if (!autoAdvance()) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalendarLinkClicked(long epochEventStartTime) {
|
||||
ActivityHelper.openCalendar(this, epochEventStartTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReply() {
|
||||
MessageCompose.actionReply(this, mMessageId, false);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReplyAll() {
|
||||
MessageCompose.actionReply(this, mMessageId, true);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onForward() {
|
||||
MessageCompose.actionForward(this, mMessageId);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBeforeMessageGone() {
|
||||
// TODO Implement this
|
||||
}
|
||||
}
|
|
@ -17,37 +17,14 @@
|
|||
package com.android.email.activity;
|
||||
|
||||
import com.android.email.Controller;
|
||||
import com.android.email.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
* Base class for {@link MessageView} and {@link MessageFileView}.
|
||||
*
|
||||
* Class relation diagram:
|
||||
* <pre>
|
||||
* (activities) (fragments)
|
||||
* MessageViewBase MessageViewFragmentBase
|
||||
* | | (with nested interface Callback)
|
||||
* | |
|
||||
* |-- MessageFileView -- owns --> |-- MessageFileViewFragment : For EML files.
|
||||
* | | (with nested interface Callback, which implements
|
||||
* | | MessageViewFragmentBase.Callback)
|
||||
* | |
|
||||
* |-- MessageView -- owns --> |-- MessageViewFragment : For regular messages
|
||||
*
|
||||
* MessageView is basically same as MessageFileView, but has more operations, such as "delete",
|
||||
* "forward", "reply", etc.
|
||||
*
|
||||
* Similarly, MessageViewFragment has more operations than MessageFileViewFragment does, such as
|
||||
* "mark unread", "respond to invite", etc. Also its Callback interface has more method than
|
||||
* MessageViewFragmentBase.Callback does, for the extra operations.
|
||||
* </pre>
|
||||
* TODO Now that MessageView is gone, we can merge it with {@link MessageFileView}.
|
||||
*/
|
||||
public abstract class MessageViewBase extends Activity implements MessageViewFragmentBase.Callback {
|
||||
private ProgressDialog mFetchAttachmentProgressDialog;
|
||||
private Controller mController;
|
||||
|
||||
protected abstract int getLayoutId();
|
||||
|
@ -58,12 +35,6 @@ public abstract class MessageViewBase extends Activity implements MessageViewFra
|
|||
ActivityHelper.debugSetWindowFlags(this);
|
||||
setContentView(getLayoutId());
|
||||
|
||||
// TODO Turn it into a "managed" dialog?
|
||||
// Managed dialogs survive activity re-creation. (e.g. orientation change)
|
||||
mFetchAttachmentProgressDialog = new ProgressDialog(this);
|
||||
mFetchAttachmentProgressDialog.setIndeterminate(true);
|
||||
mFetchAttachmentProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||
|
||||
mController = Controller.getInstance(getApplication());
|
||||
}
|
||||
|
||||
|
|
|
@ -17,12 +17,15 @@
|
|||
package com.android.email.activity;
|
||||
|
||||
import com.android.email.Email;
|
||||
import com.android.email.R;
|
||||
import com.android.email.RefreshManager;
|
||||
import com.android.email.activity.setup.AccountSettingsXL;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.provider.EmailContent.Account;
|
||||
import com.android.emailcommon.utility.EmailAsyncTask;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
@ -35,11 +38,16 @@ import java.util.ArrayList;
|
|||
/**
|
||||
* Base class for the UI controller.
|
||||
*
|
||||
* Note: Always use {@link #commitFragmentTransaction} to commit fragment transactions.
|
||||
* Note: Always use {@link #commitFragmentTransaction} and {@link #popBackStack} to operate fragment
|
||||
* transactions.
|
||||
* (Currently we use synchronous transactions only, but we may want to switch back to asynchronous
|
||||
* later.)
|
||||
*/
|
||||
abstract class UIControllerBase {
|
||||
protected static final String BUNDLE_KEY_ACCOUNT_ID = "UIController.state.account_id";
|
||||
protected static final String BUNDLE_KEY_MAILBOX_ID = "UIController.state.mailbox_id";
|
||||
protected static final String BUNDLE_KEY_MESSAGE_ID = "UIController.state.message_id";
|
||||
|
||||
/** No account selected */
|
||||
static final long NO_ACCOUNT = -1;
|
||||
/** No mailbox selected */
|
||||
|
@ -50,10 +58,10 @@ abstract class UIControllerBase {
|
|||
/** The owner activity */
|
||||
final EmailActivity mActivity;
|
||||
|
||||
final RefreshManager mRefreshManager;
|
||||
|
||||
final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker();
|
||||
|
||||
final RefreshManager mRefreshManager;
|
||||
|
||||
/**
|
||||
* List of fragments that are restored by the framework while the activity is being re-created
|
||||
* for configuration changes (e.g. screen rotation). We'll install them later when the activity
|
||||
|
@ -67,6 +75,19 @@ abstract class UIControllerBase {
|
|||
*/
|
||||
private boolean mHoldFragmentInstallation = true;
|
||||
|
||||
private final RefreshManager.Listener mRefreshListener
|
||||
= new RefreshManager.Listener() {
|
||||
@Override
|
||||
public void onMessagingError(final long accountId, long mailboxId, final String message) {
|
||||
updateRefreshProgress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefreshStatusChanged(long accountId, long mailboxId) {
|
||||
updateRefreshProgress();
|
||||
}
|
||||
};
|
||||
|
||||
public UIControllerBase(EmailActivity activity) {
|
||||
mActivity = activity;
|
||||
mRefreshManager = RefreshManager.getInstance(mActivity);
|
||||
|
@ -101,6 +122,7 @@ abstract class UIControllerBase {
|
|||
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
|
||||
Log.d(Logging.LOG_TAG, this + " onActivityCreated");
|
||||
}
|
||||
mRefreshManager.registerListener(mRefreshListener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,6 +169,7 @@ abstract class UIControllerBase {
|
|||
Log.d(Logging.LOG_TAG, this + " onActivityDestroy");
|
||||
}
|
||||
mHoldFragmentInstallation = true; // No more fragment installation.
|
||||
mRefreshManager.unregisterListener(mRefreshListener);
|
||||
mTaskTracker.cancellAllInterrupt();
|
||||
}
|
||||
|
||||
|
@ -209,6 +232,11 @@ abstract class UIControllerBase {
|
|||
}
|
||||
}
|
||||
|
||||
// not used
|
||||
void popBackStack(FragmentManager fm, String name, int flags) {
|
||||
fm.popBackStackImmediate(name, flags);
|
||||
}
|
||||
|
||||
void commitFragmentTransaction(FragmentTransaction ft) {
|
||||
ft.commit();
|
||||
mActivity.getFragmentManager().executePendingTransactions();
|
||||
|
@ -222,15 +250,29 @@ abstract class UIControllerBase {
|
|||
*/
|
||||
public abstract long getUIAccountId();
|
||||
|
||||
/**
|
||||
* @return true if an account is selected, or the current view is the combined view.
|
||||
*/
|
||||
public final boolean isAccountSelected() {
|
||||
return getUIAccountId() != NO_ACCOUNT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if an actual account is selected. (i.e. {@link Account#ACCOUNT_ID_COMBINED_VIEW}
|
||||
* is not considered "actual".s)
|
||||
*/
|
||||
public final boolean isActualAccountSelected() {
|
||||
return isAccountSelected() && (getUIAccountId() != Account.ACCOUNT_ID_COMBINED_VIEW);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently selected account ID. If the current view is the combined view,
|
||||
* it'll return {@link #NO_ACCOUNT}.
|
||||
*
|
||||
* @see #getUIAccountId()
|
||||
*/
|
||||
public long getActualAccountId() {
|
||||
final long uiAccountId = getUIAccountId();
|
||||
return uiAccountId == Account.ACCOUNT_ID_COMBINED_VIEW ? NO_ACCOUNT : uiAccountId;
|
||||
public final long getActualAccountId() {
|
||||
return isActualAccountSelected() ? getUIAccountId() : NO_ACCOUNT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -263,19 +305,71 @@ abstract class UIControllerBase {
|
|||
/**
|
||||
* Handles the {@link android.app.Activity#onCreateOptionsMenu} callback.
|
||||
*/
|
||||
public abstract boolean onCreateOptionsMenu(MenuInflater inflater, Menu menu);
|
||||
public boolean onCreateOptionsMenu(MenuInflater inflater, Menu menu) {
|
||||
inflater.inflate(R.menu.email_activity_options, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the {@link android.app.Activity#onPrepareOptionsMenu} callback.
|
||||
*/
|
||||
public abstract boolean onPrepareOptionsMenu(MenuInflater inflater, Menu menu);
|
||||
public boolean onPrepareOptionsMenu(MenuInflater inflater, Menu menu) {
|
||||
|
||||
// Update the refresh button.
|
||||
MenuItem item = menu.findItem(R.id.refresh);
|
||||
if (isRefreshEnabled()) {
|
||||
item.setVisible(true);
|
||||
if (isRefreshInProgress()) {
|
||||
item.setActionView(R.layout.action_bar_indeterminate_progress);
|
||||
} else {
|
||||
item.setActionView(null);
|
||||
}
|
||||
} else {
|
||||
item.setVisible(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the {@link android.app.Activity#onOptionsItemSelected} callback.
|
||||
*
|
||||
* @return true if the option item is handled.
|
||||
*/
|
||||
public abstract boolean onOptionsItemSelected(MenuItem item);
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
// Comes from the action bar when the app icon on the left is pressed.
|
||||
// It works like a back press, but it won't close the activity.
|
||||
return onBackPressed(false);
|
||||
case R.id.compose:
|
||||
return onCompose();
|
||||
case R.id.refresh:
|
||||
onRefresh();
|
||||
return true;
|
||||
case R.id.account_settings:
|
||||
return onAccountSettings();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the message compose activity.
|
||||
*/
|
||||
private boolean onCompose() {
|
||||
if (!isAccountSelected()) {
|
||||
return false; // this shouldn't really happen
|
||||
}
|
||||
MessageCompose.actionCompose(mActivity, getActualAccountId());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the "Settings" option item. Opens the settings activity.
|
||||
*/
|
||||
private boolean onAccountSettings() {
|
||||
AccountSettingsXL.actionSettings(mActivity, getActualAccountId());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* STOPSHIP For experimental UI. Remove this.
|
||||
|
@ -292,10 +386,30 @@ abstract class UIControllerBase {
|
|||
public abstract long getMailboxSettingsMailboxId();
|
||||
|
||||
/**
|
||||
* STOPSHIP For experimental UI. Remove this.
|
||||
* STOPSHIP For experimental UI. Make it abstract protected.
|
||||
*
|
||||
* Performs "refesh".
|
||||
*/
|
||||
public void onRefresh() {
|
||||
public abstract void onRefresh();
|
||||
|
||||
/**
|
||||
* @return true if refresh is in progress for the current mailbox.
|
||||
*/
|
||||
protected abstract boolean isRefreshInProgress();
|
||||
|
||||
/**
|
||||
* @return true if the UI should enable the "refresh" command.
|
||||
*/
|
||||
protected abstract boolean isRefreshEnabled();
|
||||
|
||||
|
||||
/**
|
||||
* Start/stop the "refresh" animation on the action bar according to the current refresh state.
|
||||
*
|
||||
* (We start the animation if {@link #isRefreshInProgress} returns true,
|
||||
* and stop otherwise.)
|
||||
*/
|
||||
protected void updateRefreshProgress() {
|
||||
mActivity.invalidateOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,57 +16,391 @@
|
|||
|
||||
package com.android.email.activity;
|
||||
|
||||
import com.android.email.Email;
|
||||
import com.android.email.R;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.provider.EmailContent.Mailbox;
|
||||
import com.android.emailcommon.utility.Utility;
|
||||
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* UI Controller for non x-large devices. Supports a single-pane layout.
|
||||
*
|
||||
* STOPSHIP Everything in this class is 100% temporary at this point
|
||||
* - Navigation model is different from what it should be (whatever it'll be).
|
||||
* e.g. when the app is launched, we should show Inbox, not mailbox list.
|
||||
*
|
||||
* - It uses the two-pane action bar only so that we can change accounts
|
||||
*
|
||||
* Major TODOs
|
||||
* - TODO Proper Navigation model, including retaining fragments to keep state such as the scroll
|
||||
* position and batch selection.
|
||||
* - TODO Nested folders
|
||||
* - TODO Newer/Older for message view
|
||||
* - TODO Implement callbacks
|
||||
*/
|
||||
class UIControllerOnePane extends UIControllerBase {
|
||||
private ActionBarController mActionBarController;
|
||||
|
||||
/**
|
||||
* Current account/mailbox/message IDs.
|
||||
* Don't use them directly; use the accessors instead, as we might want to get them from the
|
||||
* topmost fragment in the future.
|
||||
*/
|
||||
private long mCurrentAccountId = NO_ACCOUNT;
|
||||
private long mCurrentMailboxId = NO_MAILBOX;
|
||||
private long mCurrentMessageId = NO_MESSAGE;
|
||||
|
||||
private MessageCommandButtonView mMessageCommandButtons;
|
||||
|
||||
private final MailboxListFragment.Callback mMailboxListFragmentCallback =
|
||||
new MailboxListFragment.Callback() {
|
||||
@Override
|
||||
public void onAccountSelected(long accountId) {
|
||||
openAccount(accountId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCurrentMailboxUpdated(long mailboxId, String mailboxName, int unreadCount) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMailboxSelected(
|
||||
long accountId, long mailboxId, boolean navigate, boolean dragDrop) {
|
||||
open(accountId, mailboxId, NO_MESSAGE);
|
||||
}
|
||||
};
|
||||
|
||||
private final MessageListFragment.Callback mMessageListFragmentCallback =
|
||||
new MessageListFragment.Callback() {
|
||||
@Override
|
||||
public void onAdvancingOpAccepted(Set<Long> affectedMessages) {
|
||||
// Nothing to do on 1 pane.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnterSelectionMode(boolean enter) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListLoaded() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMailboxNotFound() {
|
||||
open(getUIAccountId(), NO_MAILBOX, NO_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageOpen(
|
||||
long messageId, long messageMailboxId, long listMailboxId, int type) {
|
||||
if (type == MessageListFragment.Callback.TYPE_DRAFT) {
|
||||
MessageCompose.actionEditDraft(mActivity, messageId);
|
||||
} else {
|
||||
open(getUIAccountId(), getMailboxId(), messageId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final MessageViewFragment.Callback mMessageViewFragmentCallback =
|
||||
new MessageViewFragment.Callback() {
|
||||
@Override
|
||||
public void onForward() {
|
||||
MessageCompose.actionForward(mActivity, getMessageId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReply() {
|
||||
MessageCompose.actionReply(mActivity, getMessageId(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReplyAll() {
|
||||
MessageCompose.actionReply(mActivity, getMessageId(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCalendarLinkClicked(long epochEventStartTime) {
|
||||
ActivityHelper.openCalendar(mActivity, epochEventStartTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onUrlInMessageClicked(String url) {
|
||||
return ActivityHelper.openUrlInMessage(mActivity, url, getActualAccountId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBeforeMessageGone() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageSetUnread() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRespondedToInvite(int response) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadMessageError(String errorMessage) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadMessageFinished() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadMessageStarted() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageNotExists() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageViewGone() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageViewShown(int mailboxType) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// This is all temporary as we'll have a different action bar controller for 1-pane.
|
||||
private final ActionBarController.Callback mActionBarControllerCallback
|
||||
= new ActionBarController.Callback() {
|
||||
@Override
|
||||
public boolean shouldShowMailboxName() {
|
||||
return false; // no mailbox name/unread count.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentMailboxName() {
|
||||
return null; // no mailbox name/unread count.
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentMailboxUnreadCount() {
|
||||
return 0; // no mailbox name/unread count.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldShowUp() {
|
||||
// Always show the UP arrow.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUIAccountId() {
|
||||
return UIControllerOnePane.this.getUIAccountId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountSelected() {
|
||||
return UIControllerOnePane.this.isAccountSelected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccountSelected(long accountId) {
|
||||
openAccount(accountId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNoAccountsFound() {
|
||||
Welcome.actionStart(mActivity);
|
||||
mActivity.finish();
|
||||
}
|
||||
};
|
||||
|
||||
public UIControllerOnePane(EmailActivity activity) {
|
||||
super(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putLong(BUNDLE_KEY_ACCOUNT_ID, mCurrentAccountId);
|
||||
outState.putLong(BUNDLE_KEY_MAILBOX_ID, mCurrentMailboxId);
|
||||
outState.putLong(BUNDLE_KEY_MESSAGE_ID, mCurrentMessageId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreInstanceState(Bundle savedInstanceState) {
|
||||
super.restoreInstanceState(savedInstanceState);
|
||||
mCurrentAccountId = savedInstanceState.getLong(BUNDLE_KEY_ACCOUNT_ID, NO_ACCOUNT);
|
||||
mCurrentMailboxId = savedInstanceState.getLong(BUNDLE_KEY_MAILBOX_ID, NO_MAILBOX);
|
||||
mCurrentMessageId = savedInstanceState.getLong(BUNDLE_KEY_MESSAGE_ID, NO_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLayoutId() {
|
||||
return R.layout.email_activity_one_pane;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityViewReady() {
|
||||
super.onActivityViewReady();
|
||||
mActionBarController = new ActionBarController(mActivity, mActivity.getLoaderManager(),
|
||||
mActivity.getActionBar(), mActionBarControllerCallback);
|
||||
|
||||
mMessageCommandButtons = UiUtilities.getView(mActivity, R.id.message_command_buttons);
|
||||
mMessageCommandButtons.setCallback(new CommandButtonCallback());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated() {
|
||||
super.onActivityCreated();
|
||||
mActionBarController.onActivityCreated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResume() {
|
||||
super.onActivityResume();
|
||||
refreshActionBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUIAccountId() {
|
||||
return -1;
|
||||
return mCurrentAccountId;
|
||||
}
|
||||
|
||||
private long getMailboxId() {
|
||||
return mCurrentMailboxId;
|
||||
}
|
||||
|
||||
private long getMessageId() {
|
||||
return mCurrentMessageId;
|
||||
}
|
||||
|
||||
private void refreshActionBar() {
|
||||
if (mActionBarController != null) {
|
||||
mActionBarController.refresh();
|
||||
}
|
||||
mActivity.invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
private boolean isMailboxListVisible() {
|
||||
return (getMailboxId() == NO_MAILBOX);
|
||||
}
|
||||
|
||||
private boolean isMessageListVisible() {
|
||||
return (getMailboxId() != NO_MAILBOX) && (getMessageId() == NO_MESSAGE);
|
||||
}
|
||||
|
||||
private boolean isMessageViewVisible() {
|
||||
return (getMailboxId() != NO_MAILBOX) && (getMessageId() != NO_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBackPressed(boolean isSystemBackKey) {
|
||||
return false;
|
||||
if (isMessageViewVisible()) {
|
||||
open(getUIAccountId(), getMailboxId(), NO_MESSAGE);
|
||||
return true;
|
||||
} else if (isMessageListVisible()) {
|
||||
open(getUIAccountId(), NO_MAILBOX, NO_MESSAGE);
|
||||
return true;
|
||||
} else {
|
||||
// STOPSHIP Remove this and return false. This is so that the app can be closed
|
||||
// with the UP press. (usuful when the device doesn't have a HW back key.)
|
||||
mActivity.finish();
|
||||
return true;
|
||||
// return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(MenuInflater inflater, Menu menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(MenuInflater inflater, Menu menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(long accountId, long mailboxId, long messageId) {
|
||||
void installFragment(Fragment fragment) {
|
||||
super.installFragment(fragment);
|
||||
if (fragment instanceof MailboxListFragment) {
|
||||
((MailboxListFragment) fragment).setCallback(mMailboxListFragmentCallback);
|
||||
} else if (fragment instanceof MessageListFragment) {
|
||||
((MessageListFragment) fragment).setCallback(mMessageListFragmentCallback);
|
||||
} else if (fragment instanceof MessageViewFragment) {
|
||||
((MessageViewFragment) fragment).setCallback(mMessageViewFragmentCallback);
|
||||
} else {
|
||||
// Ignore -- uninteresting fragments such as dialogs.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openAccount(long accountId) {
|
||||
open(accountId, NO_MAILBOX, NO_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(final long accountId, final long mailboxId, final long messageId) {
|
||||
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
|
||||
Log.d(Logging.LOG_TAG, this + " open accountId=" + accountId
|
||||
+ " mailboxId=" + mailboxId + " messageId=" + messageId);
|
||||
}
|
||||
if (accountId == NO_ACCOUNT) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
// !!! It's all temporary to make 1 pane UI (barely) usable !!!
|
||||
//
|
||||
// - Nested folders still doesn't work
|
||||
// - When opening a child view (e.g. message list -> message view), we should retain
|
||||
// the current fragment so that all the state (selection, scroll position, etc) will be
|
||||
// restored when back.
|
||||
|
||||
if ((getUIAccountId() == accountId) && (getMailboxId() == mailboxId)
|
||||
&& (getMessageId() == messageId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final FragmentManager fm = mActivity.getFragmentManager();
|
||||
final FragmentTransaction ft = fm.beginTransaction();
|
||||
|
||||
if (messageId != NO_MESSAGE) {
|
||||
ft.replace(R.id.fragment_placeholder, MessageViewFragment.newInstance(messageId));
|
||||
|
||||
} else if (mailboxId != NO_MAILBOX) {
|
||||
ft.replace(R.id.fragment_placeholder, MessageListFragment.newInstance(mailboxId));
|
||||
|
||||
} else {
|
||||
ft.replace(R.id.fragment_placeholder,
|
||||
MailboxListFragment.newInstance(accountId, Mailbox.PARENT_KEY_NONE));
|
||||
}
|
||||
|
||||
mCurrentAccountId = accountId;
|
||||
mCurrentMailboxId = mailboxId;
|
||||
mCurrentMessageId = messageId;
|
||||
|
||||
commitFragmentTransaction(ft);
|
||||
|
||||
refreshActionBar();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -74,7 +408,8 @@ class UIControllerOnePane extends UIControllerBase {
|
|||
*/
|
||||
@Override
|
||||
public long getMailboxSettingsMailboxId() {
|
||||
// Mailbox settigns is still experimental, and doesn't have to work on the phone.
|
||||
// Mailbox settings is still experimental, and doesn't have to work on the phone.
|
||||
Utility.showToast(mActivity, "STOPSHIP: Mailbox settings not supported on 1 pane");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -84,6 +419,51 @@ class UIControllerOnePane extends UIControllerBase {
|
|||
@Override
|
||||
public long getSearchMailboxId() {
|
||||
// Search is still experimental, and doesn't have to work on the phone.
|
||||
Utility.showToast(mActivity, "STOPSHIP: Search not supported on 1 pane");
|
||||
return -1;
|
||||
}
|
||||
|
||||
private class CommandButtonCallback implements MessageCommandButtonView.Callback {
|
||||
@Override
|
||||
public void onMoveToNewer() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoveToOlder() {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRefreshEnabled() {
|
||||
// Refreshable only when an actual account is selected, and message view isn't shown.
|
||||
// (i.e. only available on the mailbox list or the message view, but not on the combined
|
||||
// one)
|
||||
return isActualAccountSelected() && !isMessageViewVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
if (!isRefreshEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (isMessageListVisible()) {
|
||||
mRefreshManager.refreshMessageList(getActualAccountId(), getMailboxId(), true);
|
||||
} else {
|
||||
mRefreshManager.refreshMailboxList(getActualAccountId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRefreshInProgress() {
|
||||
if (!isRefreshEnabled()) {
|
||||
return false;
|
||||
}
|
||||
if (isMessageListVisible()) {
|
||||
return mRefreshManager.isMessageListRefreshing(getMailboxId());
|
||||
} else {
|
||||
return mRefreshManager.isMailboxListRefreshing(getActualAccountId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import com.android.email.Preferences;
|
|||
import com.android.email.R;
|
||||
import com.android.email.RefreshManager;
|
||||
import com.android.email.activity.setup.AccountSecurity;
|
||||
import com.android.email.activity.setup.AccountSettingsXL;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.provider.EmailContent.Account;
|
||||
import com.android.emailcommon.provider.EmailContent.Mailbox;
|
||||
|
@ -36,9 +35,6 @@ import android.app.FragmentTransaction;
|
|||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.Set;
|
||||
|
@ -53,9 +49,6 @@ class UIControllerTwoPane extends UIControllerBase implements
|
|||
MailboxListFragment.Callback,
|
||||
MessageListFragment.Callback,
|
||||
MessageViewFragment.Callback {
|
||||
private static final String BUNDLE_KEY_ACCOUNT_ID = "UIControllerTwoPane.state.account_id";
|
||||
private static final String BUNDLE_KEY_MAILBOX_ID = "UIControllerTwoPane.state.mailbox_id";
|
||||
private static final String BUNDLE_KEY_MESSAGE_ID = "UIControllerTwoPane.state.message_id";
|
||||
private static final String BUNDLE_KEY_MAILBOX_STACK
|
||||
= "UIControllerTwoPane.state.mailbox_stack";
|
||||
|
||||
|
@ -102,7 +95,6 @@ class UIControllerTwoPane extends UIControllerBase implements
|
|||
|
||||
private MailboxFinder mMailboxFinder;
|
||||
|
||||
private final RefreshListener mRefreshListener = new RefreshListener();
|
||||
private MessageOrderManager mOrderManager;
|
||||
private final MessageOrderManagerCallback mMessageOrderManagerCallback =
|
||||
new MessageOrderManagerCallback();
|
||||
|
@ -383,9 +375,7 @@ class UIControllerTwoPane extends UIControllerBase implements
|
|||
*/
|
||||
@Override
|
||||
public void onActivityViewReady() {
|
||||
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
|
||||
Log.d(Logging.LOG_TAG, this + " onActivityViewReady");
|
||||
}
|
||||
super.onActivityViewReady();
|
||||
mActionBarController = new ActionBarController(mActivity, mActivity.getLoaderManager(),
|
||||
mActivity.getActionBar(), mActionBarControllerCallback);
|
||||
|
||||
|
@ -407,17 +397,6 @@ class UIControllerTwoPane extends UIControllerBase implements
|
|||
return mAccountId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently selected account ID. If the current view is the combined view,
|
||||
* it'll return {@link #NO_ACCOUNT}.
|
||||
*
|
||||
* @see #getUIAccountId()
|
||||
*/
|
||||
@Override
|
||||
public long getActualAccountId() {
|
||||
return mAccountId == Account.ACCOUNT_ID_COMBINED_VIEW ? NO_ACCOUNT : mAccountId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the mailbox used for the message list fragment.
|
||||
* IMPORTANT: Do not confuse this with {@link #mMailboxListMailboxId} which is the id used
|
||||
|
@ -449,25 +428,19 @@ class UIControllerTwoPane extends UIControllerBase implements
|
|||
return mMessageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if an account is selected, or the current view is the combined view.
|
||||
*/
|
||||
public boolean isAccountSelected() {
|
||||
return getUIAccountId() != NO_ACCOUNT;
|
||||
}
|
||||
|
||||
public boolean isMailboxSelected() {
|
||||
private boolean isMailboxSelected() {
|
||||
return getMessageListMailboxId() != NO_MAILBOX;
|
||||
}
|
||||
|
||||
public boolean isMessageSelected() {
|
||||
private boolean isMessageSelected() {
|
||||
return getMessageId() != NO_MESSAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if refresh is in progress for the current mailbox.
|
||||
*/
|
||||
public boolean isRefreshInProgress() {
|
||||
@Override
|
||||
protected boolean isRefreshInProgress() {
|
||||
long messageListMailboxId = getMessageListMailboxId();
|
||||
return (messageListMailboxId >= 0)
|
||||
&& mRefreshManager.isMessageListRefreshing(messageListMailboxId);
|
||||
|
@ -476,7 +449,8 @@ class UIControllerTwoPane extends UIControllerBase implements
|
|||
/**
|
||||
* @return true if the UI should enable the "refresh" command.
|
||||
*/
|
||||
public boolean isRefreshEnabled() {
|
||||
@Override
|
||||
protected boolean isRefreshEnabled() {
|
||||
// - Don't show for combined inboxes, but
|
||||
// - Show even for non-refreshable mailboxes, in which case we refresh the mailbox list
|
||||
return -1 != getActualAccountId();
|
||||
|
@ -488,7 +462,6 @@ class UIControllerTwoPane extends UIControllerBase implements
|
|||
@Override
|
||||
public void onActivityCreated() {
|
||||
super.onActivityCreated();
|
||||
mRefreshManager.registerListener(mRefreshListener);
|
||||
mActionBarController.onActivityCreated();
|
||||
}
|
||||
|
||||
|
@ -525,7 +498,6 @@ class UIControllerTwoPane extends UIControllerBase implements
|
|||
@Override
|
||||
public void onActivityDestroy() {
|
||||
closeMailboxFinder();
|
||||
mRefreshManager.unregisterListener(mRefreshListener);
|
||||
super.onActivityDestroy();
|
||||
}
|
||||
|
||||
|
@ -924,43 +896,6 @@ class UIControllerTwoPane extends UIControllerBase implements
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles {@link android.app.Activity#onCreateOptionsMenu} callback.
|
||||
*/
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(MenuInflater inflater, Menu menu) {
|
||||
inflater.inflate(R.menu.email_activity_options, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(MenuInflater inflater, Menu menu) {
|
||||
ActivityHelper.updateRefreshMenuIcon(menu.findItem(R.id.refresh),
|
||||
isRefreshEnabled(),
|
||||
isRefreshInProgress());
|
||||
return true;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
// Comes from the action bar when the app icon on the left is pressed.
|
||||
// It works like a back press, but it won't close the activity.
|
||||
return onBackPressed(false);
|
||||
case R.id.compose:
|
||||
return onCompose();
|
||||
case R.id.refresh:
|
||||
onRefresh();
|
||||
return true;
|
||||
case R.id.account_settings:
|
||||
return onAccountSettings();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public boolean onBackPressed(boolean isSystemBackKey) {
|
||||
|
@ -979,25 +914,6 @@ class UIControllerTwoPane extends UIControllerBase implements
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the "Compose" option item. Opens the message compose activity.
|
||||
*/
|
||||
private boolean onCompose() {
|
||||
if (!isAccountSelected()) {
|
||||
return false; // this shouldn't really happen
|
||||
}
|
||||
MessageCompose.actionCompose(mActivity, getActualAccountId());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the "Compose" option item. Opens the settings activity.
|
||||
*/
|
||||
private boolean onAccountSettings() {
|
||||
AccountSettingsXL.actionSettings(mActivity, getActualAccountId());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the "refresh" option item. Opens the settings activity.
|
||||
* TODO used by experimental code in the activity -- otherwise can be private.
|
||||
|
@ -1009,29 +925,6 @@ class UIControllerTwoPane extends UIControllerBase implements
|
|||
getMessageListMailboxId()).cancelPreviousAndExecuteParallel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start/stop the "refresh" animation on the action bar according to the current refresh state.
|
||||
*
|
||||
* (We start the animation if {@link UIControllerTwoPane#isRefreshInProgress} returns true,
|
||||
* and stop otherwise.)
|
||||
*/
|
||||
private void updateRefreshProgress() {
|
||||
mActivity.invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
private class RefreshListener
|
||||
implements RefreshManager.Listener {
|
||||
@Override
|
||||
public void onMessagingError(final long accountId, long mailboxId, final String message) {
|
||||
updateRefreshProgress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefreshStatusChanged(long accountId, long mailboxId) {
|
||||
updateRefreshProgress();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to handle refresh.
|
||||
*
|
||||
|
|
|
@ -23,14 +23,12 @@ import com.android.email.provider.AccountBackupRestore;
|
|||
import com.android.email.service.MailService;
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.Account;
|
||||
import com.android.emailcommon.provider.EmailContent.Mailbox;
|
||||
import com.android.emailcommon.utility.EmailAsyncTask;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
@ -77,16 +75,6 @@ public class Welcome extends Activity {
|
|||
|
||||
private final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker();
|
||||
|
||||
/**
|
||||
* @return true if the obsolete phone UI should be used.
|
||||
*
|
||||
* STOPSHIP remove this. temporary support for the old activities.
|
||||
*/
|
||||
public static boolean useOldPhoneActivities(Context context) {
|
||||
final int screenLayout = context.getResources().getConfiguration().screenLayout;
|
||||
return (screenLayout & Configuration.SCREENLAYOUT_SIZE_XLARGE) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch this activity. Note: It's assumed that this activity is only called as a means to
|
||||
* 'reset' the UI state; Because of this, it is always launched with FLAG_ACTIVITY_CLEAR_TOP,
|
||||
|
@ -244,39 +232,20 @@ public class Welcome extends Activity {
|
|||
} else {
|
||||
final long accountId = resolveAccountId(mFromActivity, mAccountId, mAccountUuid);
|
||||
|
||||
// Use the old phone activities on x-large devices, only when the debug pane mode
|
||||
// is not specified.
|
||||
// If the debug pane mode is specified, always use EmailActivity.
|
||||
// STOPSHIP remove this. temporary support for the old activities.
|
||||
final boolean useOldPhoneActivities = mDebugPaneMode == 0
|
||||
&& useOldPhoneActivities(mFromActivity);
|
||||
|
||||
if (!useOldPhoneActivities) {
|
||||
final Intent i;
|
||||
if (isMessageSelected()) {
|
||||
i = EmailActivity.createOpenMessageIntent(mFromActivity, accountId,
|
||||
mMailboxId, mMessageId);
|
||||
} else if (isMailboxSelected()) {
|
||||
i = EmailActivity.createOpenMailboxIntent(mFromActivity, accountId,
|
||||
mMailboxId);
|
||||
} else {
|
||||
i = EmailActivity.createOpenAccountIntent(mFromActivity, accountId);
|
||||
}
|
||||
if (mDebugPaneMode != 0) {
|
||||
EmailActivity.forcePaneMode(i, mDebugPaneMode == 2);
|
||||
}
|
||||
mFromActivity.startActivity(i);
|
||||
final Intent i;
|
||||
if (isMessageSelected()) {
|
||||
i = EmailActivity.createOpenMessageIntent(mFromActivity, accountId,
|
||||
mMailboxId, mMessageId);
|
||||
} else if (isMailboxSelected()) {
|
||||
i = EmailActivity.createOpenMailboxIntent(mFromActivity, accountId,
|
||||
mMailboxId);
|
||||
} else {
|
||||
// STOPSHIP remove this. temporary support for the old activities.
|
||||
if (isMessageSelected()) {
|
||||
MessageView.actionView(mFromActivity, mMessageId, mMailboxId);
|
||||
} else if (isMailboxSelected()) {
|
||||
MessageList.actionHandleMailbox(mFromActivity, mMailboxId);
|
||||
} else {
|
||||
MessageList.actionHandleAccount(
|
||||
mFromActivity, accountId, Mailbox.TYPE_INBOX);
|
||||
}
|
||||
i = EmailActivity.createOpenAccountIntent(mFromActivity, accountId);
|
||||
}
|
||||
if (mDebugPaneMode != 0) {
|
||||
EmailActivity.forcePaneMode(i, mDebugPaneMode == 2);
|
||||
}
|
||||
mFromActivity.startActivity(i);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,278 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.activity;
|
||||
|
||||
import com.android.emailcommon.provider.EmailContent.Account;
|
||||
import com.android.emailcommon.provider.EmailContent.Mailbox;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.database.MergeCursor;
|
||||
import android.database.MatrixCursor.RowBuilder;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
|
||||
/**
|
||||
* Basic unit tests of AccountsAdapter
|
||||
*/
|
||||
@SmallTest
|
||||
public class AccountsAdapterTest extends AndroidTestCase {
|
||||
|
||||
private Cursor mUpperCursor = null;
|
||||
private Cursor mLowerCursor = null;
|
||||
|
||||
/**
|
||||
* Make an empty set of magic mailboxes in mUpperCursor
|
||||
*/
|
||||
private void setupUpperCursor() {
|
||||
MatrixCursor childCursor = new MatrixCursor(AccountsAdapter.MAILBOX_PROJECTION);
|
||||
mUpperCursor = childCursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a simple set of magic mailboxes in mUpperCursor
|
||||
*/
|
||||
private void populateUpperCursor() {
|
||||
MatrixCursor childCursor = (MatrixCursor) mUpperCursor;
|
||||
|
||||
int count;
|
||||
RowBuilder row;
|
||||
// TYPE_INBOX
|
||||
count = 10;
|
||||
row = childCursor.newRow();
|
||||
row.add(Long.valueOf(Mailbox.QUERY_ALL_INBOXES)); // MAILBOX_COLUMN_ID = 0;
|
||||
row.add("Inbox"); // MAILBOX_DISPLAY_NAME
|
||||
row.add(null); // MAILBOX_ACCOUNT_KEY = 2;
|
||||
row.add(Integer.valueOf(Mailbox.TYPE_INBOX)); // MAILBOX_TYPE = 3;
|
||||
row.add(Integer.valueOf(count)); // MAILBOX_UNREAD_COUNT = 4;
|
||||
// TYPE_MAIL (FAVORITES)
|
||||
count = 20;
|
||||
row = childCursor.newRow();
|
||||
row.add(Long.valueOf(Mailbox.QUERY_ALL_FAVORITES)); // MAILBOX_COLUMN_ID = 0;
|
||||
row.add("Favorites"); // MAILBOX_DISPLAY_NAME
|
||||
row.add(null); // MAILBOX_ACCOUNT_KEY = 2;
|
||||
row.add(Integer.valueOf(Mailbox.TYPE_MAIL)); // MAILBOX_TYPE = 3;
|
||||
row.add(Integer.valueOf(count)); // MAILBOX_UNREAD_COUNT = 4;
|
||||
// TYPE_DRAFTS
|
||||
count = 30;
|
||||
row = childCursor.newRow();
|
||||
row.add(Long.valueOf(Mailbox.QUERY_ALL_DRAFTS)); // MAILBOX_COLUMN_ID = 0;
|
||||
row.add("Drafts"); // MAILBOX_DISPLAY_NAME
|
||||
row.add(null); // MAILBOX_ACCOUNT_KEY = 2;
|
||||
row.add(Integer.valueOf(Mailbox.TYPE_DRAFTS)); // MAILBOX_TYPE = 3;
|
||||
row.add(Integer.valueOf(count)); // MAILBOX_UNREAD_COUNT = 4;
|
||||
// TYPE_OUTBOX
|
||||
count = 40;
|
||||
row = childCursor.newRow();
|
||||
row.add(Long.valueOf(Mailbox.QUERY_ALL_OUTBOX)); // MAILBOX_COLUMN_ID = 0;
|
||||
row.add("Outbox"); // MAILBOX_DISPLAY_NAME
|
||||
row.add(null); // MAILBOX_ACCOUNT_KEY = 2;
|
||||
row.add(Integer.valueOf(Mailbox.TYPE_OUTBOX)); // MAILBOX_TYPE = 3;
|
||||
row.add(Integer.valueOf(count)); // MAILBOX_UNREAD_COUNT = 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an empty set of accounts in mLowerCursor
|
||||
*/
|
||||
private void setupLowerCursor() {
|
||||
MatrixCursor childCursor = new MatrixCursor(Account.CONTENT_PROJECTION);
|
||||
mLowerCursor = childCursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a simple set of "accounts".
|
||||
* Note: We don't fill in the entire width of the projection because the accounts adapter
|
||||
* only looks at a few of the columns anyway.
|
||||
*/
|
||||
private void populateLowerCursor() {
|
||||
MatrixCursor childCursor = (MatrixCursor) mLowerCursor;
|
||||
|
||||
RowBuilder row;
|
||||
// Account #1
|
||||
row = childCursor.newRow();
|
||||
row.add(Long.valueOf(1)); // CONTENT_ID_COLUMN = 0;
|
||||
row.add("Account 1"); // CONTENT_DISPLAY_NAME_COLUMN = 1;
|
||||
row.add("account1@android.com"); // CONTENT_EMAIL_ADDRESS_COLUMN = 2;
|
||||
// Account #2
|
||||
row = childCursor.newRow();
|
||||
row.add(Long.valueOf(2)); // CONTENT_ID_COLUMN = 0;
|
||||
row.add("Account 2"); // CONTENT_DISPLAY_NAME_COLUMN = 1;
|
||||
row.add("account2@android.com"); // CONTENT_EMAIL_ADDRESS_COLUMN = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test: General handling of separator
|
||||
*/
|
||||
public void testSeparator() {
|
||||
// Test with fully populated upper and lower sections
|
||||
setupUpperCursor();
|
||||
populateUpperCursor();
|
||||
setupLowerCursor();
|
||||
populateLowerCursor();
|
||||
AccountsAdapter adapter = AccountsAdapter.getInstance(mUpperCursor, mLowerCursor,
|
||||
getContext(), -1, null);
|
||||
checkAdapter("fully populated", adapter, mUpperCursor, mLowerCursor);
|
||||
|
||||
// Test with empty upper and populated lower
|
||||
setupUpperCursor();
|
||||
setupLowerCursor();
|
||||
populateLowerCursor();
|
||||
adapter = AccountsAdapter.getInstance(mUpperCursor, mLowerCursor, getContext(), -1, null);
|
||||
checkAdapter("lower populated", adapter, mUpperCursor, mLowerCursor);
|
||||
|
||||
// Test with both empty
|
||||
setupUpperCursor();
|
||||
setupLowerCursor();
|
||||
adapter = AccountsAdapter.getInstance(mUpperCursor, mLowerCursor, getContext(), -1, null);
|
||||
checkAdapter("both empty", adapter, mUpperCursor, mLowerCursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to check the various APIs related to the upper/lower separator
|
||||
*/
|
||||
private void checkAdapter(String tag, AccountsAdapter adapter, Cursor upper, Cursor lower) {
|
||||
// Check total count
|
||||
int expectedCount = 0;
|
||||
if (upper != null) expectedCount += upper.getCount();
|
||||
if (lower != null) expectedCount += lower.getCount();
|
||||
// If one or more items are shown, the adapter inserts the separator as well
|
||||
if (expectedCount > 0) expectedCount++;
|
||||
assertEquals(tag, expectedCount, adapter.getCount());
|
||||
|
||||
// Check separator-related APIs
|
||||
int separatorIndex = -1;
|
||||
if (upper != null) {
|
||||
separatorIndex = upper.getCount();
|
||||
}
|
||||
|
||||
// Get the MergeCursor that the adapter created
|
||||
MergeCursor mc = (MergeCursor) adapter.getCursor();
|
||||
|
||||
// Check APIs for the position above the separator index
|
||||
// This will be the last entry in the "upper" cursor
|
||||
if (separatorIndex > 0) {
|
||||
int checkIndex = separatorIndex - 1;
|
||||
assertTrue(tag, adapter.isMailbox(checkIndex));
|
||||
assertFalse(tag, adapter.isAccount(checkIndex));
|
||||
assertTrue(tag, adapter.isEnabled(checkIndex));
|
||||
Cursor c = (Cursor) adapter.getItem(checkIndex);
|
||||
assertEquals(tag, mc, c);
|
||||
assertEquals(tag, checkIndex, c.getPosition());
|
||||
upper.moveToLast();
|
||||
long id = upper.getLong(0);
|
||||
assertEquals(tag, id, adapter.getItemId(checkIndex));
|
||||
}
|
||||
|
||||
// Check APIs for position at the separator index
|
||||
if (separatorIndex >= 0) {
|
||||
int checkIndex = separatorIndex;
|
||||
assertFalse(tag, adapter.isMailbox(checkIndex));
|
||||
assertFalse(tag, adapter.isAccount(checkIndex));
|
||||
assertFalse(tag, adapter.isEnabled(checkIndex));
|
||||
// getItem and getItemId should never be called because it should not be enabled
|
||||
}
|
||||
|
||||
// Check APIs for the position below the separator index
|
||||
// This will be the first entry in the "lower" cursor
|
||||
if (lower != null && lower.getCount() > 0) {
|
||||
int checkIndex = separatorIndex + 1;
|
||||
assertFalse(tag, adapter.isMailbox(checkIndex));
|
||||
assertTrue(tag, adapter.isAccount(checkIndex));
|
||||
assertTrue(tag, adapter.isEnabled(checkIndex));
|
||||
Cursor c = (Cursor) adapter.getItem(checkIndex);
|
||||
assertEquals(tag, mc, c);
|
||||
assertEquals(tag, separatorIndex, c.getPosition());
|
||||
lower.moveToFirst();
|
||||
long id = lower.getLong(0);
|
||||
assertEquals(tag, id, adapter.getItemId(checkIndex));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test: isOnDeletingAccountView
|
||||
*/
|
||||
public void testDeletingAccount() {
|
||||
// Test with fully populated upper and lower sections
|
||||
setupUpperCursor();
|
||||
populateUpperCursor();
|
||||
setupLowerCursor();
|
||||
populateLowerCursor();
|
||||
AccountsAdapter adapter = AccountsAdapter.getInstance(mUpperCursor, mLowerCursor,
|
||||
getContext(), -1, null);
|
||||
|
||||
// Check enabled state - all should be enabled except for separator
|
||||
for (int i = 0; i < adapter.getCount(); i++) {
|
||||
boolean expectEnabled = adapter.isMailbox(i) || adapter.isAccount(i);
|
||||
assertEquals(expectEnabled, adapter.isEnabled(i));
|
||||
}
|
||||
|
||||
// "Delete" the first account
|
||||
adapter.addOnDeletingAccount(1); // account Id of 1st account
|
||||
int account1Position = mUpperCursor.getCount() + 1; // first entry after separator
|
||||
for (int i = 0; i < adapter.getCount(); i++) {
|
||||
boolean isNotSeparator = adapter.isMailbox(i) || adapter.isAccount(i);
|
||||
boolean expectEnabled = isNotSeparator && (i != account1Position);
|
||||
assertEquals(expectEnabled, adapter.isEnabled(i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test: callback(s)
|
||||
*/
|
||||
public void testCallbacks() {
|
||||
// Test with fully populated upper and lower sections
|
||||
setupUpperCursor();
|
||||
populateUpperCursor();
|
||||
setupLowerCursor();
|
||||
populateLowerCursor();
|
||||
Callback cb = new Callback();
|
||||
AccountsAdapter adapter = AccountsAdapter.getInstance(mUpperCursor, mLowerCursor,
|
||||
getContext(), -1, cb);
|
||||
|
||||
AccountFolderListItem itemView = new AccountFolderListItem(mContext);
|
||||
itemView.mAccountId = 1;
|
||||
adapter.onClickFolder(itemView);
|
||||
assertTrue(cb.called);
|
||||
assertEquals(1, cb.id);
|
||||
}
|
||||
|
||||
private static class Callback implements AccountsAdapter.Callback {
|
||||
public boolean called = false;
|
||||
public long id = -1;
|
||||
|
||||
public void onClickAccountFolders(long accountId) {
|
||||
called = true;
|
||||
id = accountId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for cursor management. Make sure that the underlying cursor is closed properly
|
||||
* when we set the cursor to null.
|
||||
*/
|
||||
public void testCursorManagement() {
|
||||
setupUpperCursor();
|
||||
setupLowerCursor();
|
||||
AccountsAdapter adapter = AccountsAdapter.getInstance(mUpperCursor, mLowerCursor,
|
||||
getContext(), -1, null);
|
||||
|
||||
Cursor c = adapter.getCursor();
|
||||
assertFalse(c.isClosed());
|
||||
adapter.changeCursor(null);
|
||||
assertTrue(c.isClosed());
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ import android.net.Uri;
|
|||
import android.test.ActivityInstrumentationTestCase2;
|
||||
|
||||
/**
|
||||
* Test case for {@link MessageTestView}.
|
||||
* Test case for {@link MessageFileView}.
|
||||
*
|
||||
* TODO Add more tests. Any good way to test fragment??
|
||||
*/
|
||||
|
@ -49,7 +49,7 @@ public class MessageFileViewTest extends ActivityInstrumentationTestCase2<Messag
|
|||
}
|
||||
|
||||
private void setUpIntent(Uri uri) {
|
||||
final Intent i = new Intent(getInstrumentation().getTargetContext(), MessageView.class);
|
||||
final Intent i = new Intent(getInstrumentation().getTargetContext(), MessageFileView.class);
|
||||
i.setData(uri);
|
||||
setActivityIntent(i);
|
||||
}
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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.android.email.activity;
|
||||
|
||||
import com.android.email.DBTestHelper;
|
||||
import com.android.email.TestUtils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
|
||||
/**
|
||||
* Test case for {@link MessageView}.
|
||||
*
|
||||
* TODO Add more tests. Any good way to test fragment??
|
||||
*/
|
||||
public class MessageViewTest extends ActivityInstrumentationTestCase2<MessageView> {
|
||||
private static final String EXTRA_MESSAGE_ID = "com.android.email.MessageView_message_id";
|
||||
private static final String EXTRA_DISABLE_REPLY =
|
||||
"com.android.email.MessageView_disable_reply";
|
||||
private static final String EXTRA_MAILBOX_ID = "com.android.email.MessageView_mailbox_id";
|
||||
|
||||
private static int TIMEOUT = 10; // in seconds
|
||||
|
||||
private Context mProviderContext;
|
||||
|
||||
public MessageViewTest() {
|
||||
super(MessageView.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mProviderContext = DBTestHelper.ProviderContextSetupHelper.getProviderContext(
|
||||
getInstrumentation().getTargetContext());
|
||||
}
|
||||
|
||||
private void setUpIntent(long messageId, long mailboxId, boolean disableReply) {
|
||||
final Intent i = new Intent(getInstrumentation().getTargetContext(), MessageView.class);
|
||||
i.putExtra(EXTRA_MESSAGE_ID, messageId);
|
||||
i.putExtra(EXTRA_MAILBOX_ID, mailboxId);
|
||||
if (disableReply) {
|
||||
i.putExtra(EXTRA_DISABLE_REPLY, true);
|
||||
}
|
||||
setActivityIntent(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the activity without setting an Intent.
|
||||
*
|
||||
* Expected: Activity will close itself.
|
||||
*/
|
||||
public void testCreateWithoutParamter() throws Throwable {
|
||||
// No intent parameters specified. The activity will close itself.
|
||||
final MessageView activity = getActivity();
|
||||
|
||||
TestUtils.waitUntil("", new TestUtils.Condition() {
|
||||
@Override
|
||||
public boolean isMet() {
|
||||
return activity.isFinishing();
|
||||
}
|
||||
}, TIMEOUT);
|
||||
}
|
||||
|
||||
// This test doesn't work, because it sets up messages in an separated context, but
|
||||
// the main activity looks at the actual context and fails to find the message.
|
||||
// /**
|
||||
// * Set up account/mailbox/message, and open the activity.
|
||||
// *
|
||||
// * Expected: Message opens.
|
||||
// */
|
||||
// public void testOpenMessage() throws Exception {
|
||||
// final Context c = mProviderContext;
|
||||
// final Account acct1 = ProviderTestUtils.setupAccount("test1", true, c);
|
||||
// final Account acct2 = ProviderTestUtils.setupAccount("test2", true, c);
|
||||
// final Mailbox acct2inbox = ProviderTestUtils.setupMailbox("inbox", acct2.mId, true, c);
|
||||
// final Message msg1 = ProviderTestUtils.setupMessage("message1", acct2.mId, acct2inbox.mId,
|
||||
// true, true, c);
|
||||
// final Message msg2 = ProviderTestUtils.setupMessage("message2", acct2.mId, acct2inbox.mId,
|
||||
// true, true, c);
|
||||
//
|
||||
// setUpIntent(msg2.mId, msg2.mMailboxKey, false);
|
||||
//
|
||||
// final MessageView activity = getActivity();
|
||||
//
|
||||
// TestUtils.waitUntil(new TestUtils.Condition() {
|
||||
// @Override
|
||||
// public boolean isMet() {
|
||||
// MessageViewFragment f = activity.getFragment();
|
||||
// return f != null && f.isMessageLoadedForTest();
|
||||
// }
|
||||
// }, TIMEOUT);
|
||||
//
|
||||
// // TODO Check UI elements, once our UI is settled.
|
||||
// }
|
||||
}
|