1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-30 05:02:26 -05:00

Merge branch 'ideal-screenreader'

* ideal-screenreader:
  The IDEAL Group have joined the K-9 dogwalkers and submitted their code to be part of K-9!
  Initial import of the Ideal K-9 branch which adds support for screenreaders.
This commit is contained in:
Jesse Vincent 2010-08-18 02:01:10 +00:00
parent 5be5aaa44a
commit 86dc82f916
15 changed files with 297 additions and 4 deletions

View File

@ -246,6 +246,10 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name="com.fsck.k9.AccessibleEmailContentActivity"
>
</activity>
<receiver android:name="com.fsck.k9.service.BootReceiver" <receiver android:name="com.fsck.k9.service.BootReceiver"
android:enabled="true" android:enabled="true"

0
res/drawable/btn_check_buttonless_off.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 546 B

After

Width:  |  Height:  |  Size: 546 B

0
res/drawable/btn_check_buttonless_on.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 384 B

After

Width:  |  Height:  |  Size: 384 B

0
res/drawable/btn_check_small_off.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 362 B

After

Width:  |  Height:  |  Size: 362 B

0
res/drawable/btn_check_small_on.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 294 B

After

Width:  |  Height:  |  Size: 294 B

0
res/drawable/btn_dialog_disable.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

0
res/drawable/btn_dialog_normal.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

0
res/drawable/btn_dialog_pressed.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

0
res/drawable/btn_dialog_selected.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>

View File

@ -251,6 +251,10 @@
android:id="@+id/message_content" android:id="@+id/message_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="fill_parent" /> android:layout_width="fill_parent" />
<com.fsck.k9.web.AccessibleWebView
android:id="@+id/accessible_message_content"
android:layout_height="wrap_content"
android:layout_width="fill_parent" />
<!-- Attachments area --> <!-- Attachments area -->
<LinearLayout <LinearLayout
android:id="@+id/attachments" android:id="@+id/attachments"

View File

@ -16,9 +16,12 @@ import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Typeface; import android.graphics.Typeface;
@ -77,6 +80,7 @@ import com.fsck.k9.mail.store.LocalStore.LocalAttachmentBodyPart;
import com.fsck.k9.mail.store.LocalStore.LocalMessage; import com.fsck.k9.mail.store.LocalStore.LocalMessage;
import com.fsck.k9.mail.store.LocalStore.LocalTextBody; import com.fsck.k9.mail.store.LocalStore.LocalTextBody;
import com.fsck.k9.provider.AttachmentProvider; import com.fsck.k9.provider.AttachmentProvider;
import com.fsck.k9.web.AccessibleWebView;
public class MessageView extends K9Activity implements OnClickListener public class MessageView extends K9Activity implements OnClickListener
{ {
@ -106,6 +110,11 @@ public class MessageView extends K9Activity implements OnClickListener
private TextView mCryptoSignatureUserId = null; private TextView mCryptoSignatureUserId = null;
private TextView mCryptoSignatureUserIdRest = null; private TextView mCryptoSignatureUserIdRest = null;
private WebView mMessageContentView; private WebView mMessageContentView;
private boolean mScreenReaderEnabled;
private AccessibleWebView mAccessibleMessageContentView;
private LinearLayout mHeaderContainer; private LinearLayout mHeaderContainer;
private LinearLayout mAttachments; private LinearLayout mAttachments;
private LinearLayout mToContainerView; private LinearLayout mToContainerView;
@ -285,9 +294,16 @@ public class MessageView extends K9Activity implements OnClickListener
mHandler.post(new Runnable() mHandler.post(new Runnable()
{ {
public void run() public void run()
{
if (mScreenReaderEnabled)
{
mAccessibleMessageContentView.zoomIn();
}
else
{ {
mMessageContentView.zoomIn(); mMessageContentView.zoomIn();
} }
}
}); });
} }
else else
@ -295,9 +311,16 @@ public class MessageView extends K9Activity implements OnClickListener
mHandler.post(new Runnable() mHandler.post(new Runnable()
{ {
public void run() public void run()
{
if (mScreenReaderEnabled)
{
mAccessibleMessageContentView.zoomIn();
}
else
{ {
mMessageContentView.zoomOut(); mMessageContentView.zoomOut();
} }
}
}); });
} }
return true; return true;
@ -749,6 +772,20 @@ public class MessageView extends K9Activity implements OnClickListener
mTimeView = (TextView)findViewById(R.id.time); mTimeView = (TextView)findViewById(R.id.time);
mTopView = mToggleScrollView = (ToggleScrollView)findViewById(R.id.top_view); mTopView = mToggleScrollView = (ToggleScrollView)findViewById(R.id.top_view);
mMessageContentView = (WebView)findViewById(R.id.message_content); mMessageContentView = (WebView)findViewById(R.id.message_content);
mAccessibleMessageContentView = (AccessibleWebView) findViewById(R.id.accessible_message_content);
mScreenReaderEnabled = isScreenReaderActive();
if (mScreenReaderEnabled)
{
mAccessibleMessageContentView.setVisibility(View.VISIBLE);
mMessageContentView.setVisibility(View.GONE);
}
else
{
mAccessibleMessageContentView.setVisibility(View.GONE);
mMessageContentView.setVisibility(View.VISIBLE);
}
mDecryptLayout = (View)findViewById(R.id.layout_decrypt); mDecryptLayout = (View)findViewById(R.id.layout_decrypt);
mDecryptButton = (Button)findViewById(R.id.btn_decrypt); mDecryptButton = (Button)findViewById(R.id.btn_decrypt);
@ -1002,6 +1039,43 @@ public class MessageView extends K9Activity implements OnClickListener
displayMessage(mMessageReference); displayMessage(mMessageReference);
} }
private boolean isScreenReaderActive()
{
final String SCREENREADER_INTENT_ACTION = "android.accessibilityservice.AccessibilityService";
final String SCREENREADER_INTENT_CATEGORY = "android.accessibilityservice.category.FEEDBACK_SPOKEN";
// Restrict the set of intents to only accessibility services that have
// the category FEEDBACK_SPOKEN (aka, screen readers).
Intent screenReaderIntent = new Intent(SCREENREADER_INTENT_ACTION);
screenReaderIntent.addCategory(SCREENREADER_INTENT_CATEGORY);
List<ResolveInfo> screenReaders = getPackageManager().queryIntentServices(
screenReaderIntent, 0);
ContentResolver cr = getContentResolver();
Cursor cursor = null;
int status = 0;
for (ResolveInfo screenReader : screenReaders)
{
// All screen readers are expected to implement a content provider
// that responds to
// content://<nameofpackage>.providers.StatusProvider
cursor = cr.query(Uri.parse("content://" + screenReader.serviceInfo.packageName
+ ".providers.StatusProvider"), null, null, null, null);
if (cursor != null)
{
cursor.moveToFirst();
// These content providers use a special cursor that only has
// one element,
// an integer that is 1 if the screen reader is running.
status = cursor.getInt(0);
cursor.close();
if (status == 1)
{
return true;
}
}
}
return false;
}
@Override @Override
protected void onSaveInstanceState(Bundle outState) protected void onSaveInstanceState(Bundle outState)
{ {
@ -2127,9 +2201,18 @@ public class MessageView extends K9Activity implements OnClickListener
{ {
public void run() public void run()
{ {
mMessageContentView.loadDataWithBaseURL("http://", emailText, mimeType, "utf-8", null);
mTopView.scrollTo(0, 0); mTopView.scrollTo(0, 0);
if (mScreenReaderEnabled)
{
mAccessibleMessageContentView.loadDataWithBaseURL("http://",
emailText, "text/html", "utf-8", null);
}
else
{
mMessageContentView.loadDataWithBaseURL("http://", emailText,
"text/html", "utf-8", null);
mMessageContentView.scrollTo(0, 0); mMessageContentView.scrollTo(0, 0);
}
updateDecryptLayout(); updateDecryptLayout();
} }
}); });

View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2010 The IDEAL Group
*
* 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.fsck.k9.web;
import java.util.ArrayList;
import android.app.ListActivity;
import android.os.Bundle;
import android.text.Html;
import android.text.Spanned;
import android.widget.ArrayAdapter;
public class AccessibleEmailContentActivity extends ListActivity {
String[] listItems = {
""
};
private String htmlSource;
private ArrayList<String> cleanedList;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
htmlSource = getIntent().getStringExtra("content");
Spanned parsedHtml = Html.fromHtml(htmlSource, null, null);
String[] rawListItems = parsedHtml.toString().split("\n");
cleanedList = new ArrayList<String>();
for (int i = 0; i < rawListItems.length; i++) {
if (rawListItems[i].trim().length() > 0) {
addToCleanedList(rawListItems[i]);
}
}
listItems = cleanedList.toArray(listItems);
setContentView(com.fsck.k9.R.layout.accessible_email_content);
setListAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, listItems));
}
private void addToCleanedList(String line) {
if (line.length() < 80) {
cleanedList.add(line);
} else {
while (line.length() > 80) {
int cutPoint = line.indexOf(" ", 80);
if ((cutPoint > 0) && (cutPoint < line.length())) {
cleanedList.add(line.substring(0, cutPoint));
line = line.substring(cutPoint).trim();
} else {
cleanedList.add(line);
line = "";
}
}
if (line.length() > 0) {
cleanedList.add(line);
}
}
}
}

View File

@ -0,0 +1,112 @@
/*
* Copyright (C) 2010 The IDEAL Group
*
* 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.fsck.k9.web;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.text.Html;
import android.util.AttributeSet;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.TextView;
public class AccessibleWebView extends TextView {
private Activity parent;
private String htmlSource;
private WebView dummyWebView;
public AccessibleWebView(Context context) {
super(context);
parent = (Activity) context;
dummyWebView = new WebView(context);
setFocusable(true);
setFocusableInTouchMode(true);
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
diveIn();
}
});
}
public AccessibleWebView(Context context, AttributeSet attributes) {
super(context, attributes);
parent = (Activity) context;
dummyWebView = new WebView(context);
setFocusable(true);
setFocusableInTouchMode(true);
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
diveIn();
}
});
}
public void loadData(String data, String mimeType, String encoding) {
htmlSource = data;
this.setText(Html.fromHtml(htmlSource, null, null));
}
public WebSettings getSettings() {
return dummyWebView.getSettings();
}
public void setVerticalScrollbarOverlay(boolean booleanValue) {
// Do nothing here; dummy stub method to maintain compatibility with
// standard WebView.
}
public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding,
String historyUrl) {
htmlSource = data;
this.setText(Html.fromHtml(htmlSource, null, null));
}
public void loadUrl(String url) {
// Do nothing here; dummy stub method to maintain compatibility with
// standard WebView.
}
public boolean zoomIn() {
if (getTextSize() < 100) {
setTextSize(getTextSize() + 5);
return true;
}
return false;
}
public boolean zoomOut() {
if (getTextSize() > 5) {
setTextSize(getTextSize() - 5);
return true;
}
return false;
}
private void diveIn() {
Intent i = new Intent();
i.setClass(parent, AccessibleEmailContentActivity.class);
i.putExtra("content", htmlSource);
parent.startActivity(i);
}
}

0
tools/build-beta Executable file → Normal file
View File